diff options
435 files changed, 12048 insertions, 4787 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 1c56d45b16..3ca814850e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -406,7 +406,7 @@ Guest CPU Cores (Xen) X86 Xen CPUs M: Stefano Stabellini <sstabellini@kernel.org> M: Anthony Perard <anthony.perard@citrix.com> -M: Paul Durrant <paul.durrant@citrix.com> +M: Paul Durrant <paul@xen.org> L: xen-devel@lists.xenproject.org S: Supported F: */xen* @@ -1077,8 +1077,6 @@ F: hw/*/spapr* F: include/hw/*/spapr* F: hw/*/xics* F: include/hw/*/xics* -F: pc-bios/spapr-rtas/* -F: pc-bios/spapr-rtas.bin F: pc-bios/slof.bin F: docs/specs/ppc-spapr-hcalls.txt F: docs/specs/ppc-spapr-hotplug.txt @@ -1206,7 +1204,7 @@ T: git https://github.com/borntraeger/qemu.git s390-next L: qemu-s390x@nongnu.org S390 PCI -M: Collin Walling <walling@linux.ibm.com> +M: Matthew Rosato <mjrosato@linux.ibm.com> S: Supported F: hw/s390x/s390-pci* L: qemu-s390x@nongnu.org @@ -510,7 +510,11 @@ capstone/all: .git-submodule-status .PHONY: slirp/all slirp/all: .git-submodule-status - $(call quiet-command,$(MAKE) -C $(SRC_PATH)/slirp BUILD_DIR="$(BUILD_DIR)/slirp" CC="$(CC)" AR="$(AR)" LD="$(LD)" RANLIB="$(RANLIB)" CFLAGS="$(QEMU_CFLAGS) $(CFLAGS)" LDFLAGS="$(LDFLAGS)") + $(call quiet-command,$(MAKE) -C $(SRC_PATH)/slirp \ + BUILD_DIR="$(BUILD_DIR)/slirp" \ + PKG_CONFIG="$(PKG_CONFIG)" \ + CC="$(CC)" AR="$(AR)" LD="$(LD)" RANLIB="$(RANLIB)" \ + CFLAGS="$(QEMU_CFLAGS) $(CFLAGS)" LDFLAGS="$(LDFLAGS)") # Compatibility gunk to keep make working across the rename of targets # for recursion, to be removed some time after 4.1. @@ -765,7 +769,7 @@ qemu-nsis.bmp \ bamboo.dtb canyonlands.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \ multiboot.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin pvh.bin \ s390-ccw.img s390-netboot.img \ -spapr-rtas.bin slof.bin skiboot.lid \ +slof.bin skiboot.lid \ palcode-clipper \ u-boot.e500 u-boot-sam460-20100605.bin \ qemu_vga.ndrv \ diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index b09bad0804..d2d96d73e8 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -140,6 +140,7 @@ bool kvm_direct_msi_allowed; bool kvm_ioeventfd_any_length_allowed; bool kvm_msi_use_devid; static bool kvm_immediate_exit; +static hwaddr kvm_max_slot_size = ~0; static const KVMCapabilityInfo kvm_required_capabilites[] = { KVM_CAP_INFO(USER_MEMORY), @@ -437,7 +438,7 @@ static int kvm_slot_update_flags(KVMMemoryListener *kml, KVMSlot *mem, static int kvm_section_update_flags(KVMMemoryListener *kml, MemoryRegionSection *section) { - hwaddr start_addr, size; + hwaddr start_addr, size, slot_size; KVMSlot *mem; int ret = 0; @@ -448,13 +449,18 @@ static int kvm_section_update_flags(KVMMemoryListener *kml, kvm_slots_lock(kml); - mem = kvm_lookup_matching_slot(kml, start_addr, size); - if (!mem) { - /* We don't have a slot if we want to trap every access. */ - goto out; - } + while (size && !ret) { + slot_size = MIN(kvm_max_slot_size, size); + mem = kvm_lookup_matching_slot(kml, start_addr, slot_size); + if (!mem) { + /* We don't have a slot if we want to trap every access. */ + goto out; + } - ret = kvm_slot_update_flags(kml, mem, section->mr); + ret = kvm_slot_update_flags(kml, mem, section->mr); + start_addr += slot_size; + size -= slot_size; + } out: kvm_slots_unlock(kml); @@ -527,11 +533,15 @@ static int kvm_physical_sync_dirty_bitmap(KVMMemoryListener *kml, struct kvm_dirty_log d = {}; KVMSlot *mem; hwaddr start_addr, size; + hwaddr slot_size, slot_offset = 0; int ret = 0; size = kvm_align_section(section, &start_addr); - if (size) { - mem = kvm_lookup_matching_slot(kml, start_addr, size); + while (size) { + MemoryRegionSection subsection = *section; + + slot_size = MIN(kvm_max_slot_size, size); + mem = kvm_lookup_matching_slot(kml, start_addr, slot_size); if (!mem) { /* We don't have a slot if we want to trap every access. */ goto out; @@ -549,11 +559,11 @@ static int kvm_physical_sync_dirty_bitmap(KVMMemoryListener *kml, * So for now, let's align to 64 instead of HOST_LONG_BITS here, in * a hope that sizeof(long) won't become >8 any time soon. */ - size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS), - /*HOST_LONG_BITS*/ 64) / 8; if (!mem->dirty_bmap) { + hwaddr bitmap_size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS), + /*HOST_LONG_BITS*/ 64) / 8; /* Allocate on the first log_sync, once and for all */ - mem->dirty_bmap = g_malloc0(size); + mem->dirty_bmap = g_malloc0(bitmap_size); } d.dirty_bitmap = mem->dirty_bmap; @@ -564,7 +574,13 @@ static int kvm_physical_sync_dirty_bitmap(KVMMemoryListener *kml, goto out; } - kvm_get_dirty_pages_log_range(section, d.dirty_bitmap); + subsection.offset_within_region += slot_offset; + subsection.size = int128_make64(slot_size); + kvm_get_dirty_pages_log_range(&subsection, d.dirty_bitmap); + + slot_offset += slot_size; + start_addr += slot_size; + size -= slot_size; } out: return ret; @@ -575,63 +591,22 @@ out: #define KVM_CLEAR_LOG_ALIGN (qemu_real_host_page_size << KVM_CLEAR_LOG_SHIFT) #define KVM_CLEAR_LOG_MASK (-KVM_CLEAR_LOG_ALIGN) -/** - * kvm_physical_log_clear - Clear the kernel's dirty bitmap for range - * - * NOTE: this will be a no-op if we haven't enabled manual dirty log - * protection in the host kernel because in that case this operation - * will be done within log_sync(). - * - * @kml: the kvm memory listener - * @section: the memory range to clear dirty bitmap - */ -static int kvm_physical_log_clear(KVMMemoryListener *kml, - MemoryRegionSection *section) +static int kvm_log_clear_one_slot(KVMSlot *mem, int as_id, uint64_t start, + uint64_t size) { KVMState *s = kvm_state; + uint64_t end, bmap_start, start_delta, bmap_npages; struct kvm_clear_dirty_log d; - uint64_t start, end, bmap_start, start_delta, bmap_npages, size; unsigned long *bmap_clear = NULL, psize = qemu_real_host_page_size; - KVMSlot *mem = NULL; - int ret, i; - - if (!s->manual_dirty_log_protect) { - /* No need to do explicit clear */ - return 0; - } - - start = section->offset_within_address_space; - size = int128_get64(section->size); - - if (!size) { - /* Nothing more we can do... */ - return 0; - } - - kvm_slots_lock(kml); - - /* Find any possible slot that covers the section */ - for (i = 0; i < s->nr_slots; i++) { - mem = &kml->slots[i]; - if (mem->start_addr <= start && - start + size <= mem->start_addr + mem->memory_size) { - break; - } - } - - /* - * We should always find one memslot until this point, otherwise - * there could be something wrong from the upper layer - */ - assert(mem && i != s->nr_slots); + int ret; /* * We need to extend either the start or the size or both to * satisfy the KVM interface requirement. Firstly, do the start * page alignment on 64 host pages */ - bmap_start = (start - mem->start_addr) & KVM_CLEAR_LOG_MASK; - start_delta = start - mem->start_addr - bmap_start; + bmap_start = start & KVM_CLEAR_LOG_MASK; + start_delta = start - bmap_start; bmap_start /= psize; /* @@ -694,7 +669,7 @@ static int kvm_physical_log_clear(KVMMemoryListener *kml, /* It should never overflow. If it happens, say something */ assert(bmap_npages <= UINT32_MAX); d.num_pages = bmap_npages; - d.slot = mem->slot | (kml->as_id << 16); + d.slot = mem->slot | (as_id << 16); if (kvm_vm_ioctl(s, KVM_CLEAR_DIRTY_LOG, &d) == -1) { ret = -errno; @@ -717,6 +692,66 @@ static int kvm_physical_log_clear(KVMMemoryListener *kml, size / psize); /* This handles the NULL case well */ g_free(bmap_clear); + return ret; +} + + +/** + * kvm_physical_log_clear - Clear the kernel's dirty bitmap for range + * + * NOTE: this will be a no-op if we haven't enabled manual dirty log + * protection in the host kernel because in that case this operation + * will be done within log_sync(). + * + * @kml: the kvm memory listener + * @section: the memory range to clear dirty bitmap + */ +static int kvm_physical_log_clear(KVMMemoryListener *kml, + MemoryRegionSection *section) +{ + KVMState *s = kvm_state; + uint64_t start, size, offset, count; + KVMSlot *mem; + int ret = 0, i; + + if (!s->manual_dirty_log_protect) { + /* No need to do explicit clear */ + return ret; + } + + start = section->offset_within_address_space; + size = int128_get64(section->size); + + if (!size) { + /* Nothing more we can do... */ + return ret; + } + + kvm_slots_lock(kml); + + for (i = 0; i < s->nr_slots; i++) { + mem = &kml->slots[i]; + /* Discard slots that are empty or do not overlap the section */ + if (!mem->memory_size || + mem->start_addr > start + size - 1 || + start > mem->start_addr + mem->memory_size - 1) { + continue; + } + + if (start >= mem->start_addr) { + /* The slot starts before section or is aligned to it. */ + offset = start - mem->start_addr; + count = MIN(mem->memory_size - offset, size); + } else { + /* The slot starts after section. */ + offset = 0; + count = MIN(mem->memory_size, size - (mem->start_addr - start)); + } + ret = kvm_log_clear_one_slot(mem, kml->as_id, offset, count); + if (ret < 0) { + break; + } + } kvm_slots_unlock(kml); @@ -953,6 +988,14 @@ kvm_check_extension_list(KVMState *s, const KVMCapabilityInfo *list) return NULL; } +void kvm_set_max_memslot_size(hwaddr max_slot_size) +{ + g_assert( + ROUND_UP(max_slot_size, qemu_real_host_page_size) == max_slot_size + ); + kvm_max_slot_size = max_slot_size; +} + static void kvm_set_phys_mem(KVMMemoryListener *kml, MemoryRegionSection *section, bool add) { @@ -960,7 +1003,7 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml, int err; MemoryRegion *mr = section->mr; bool writeable = !mr->readonly && !mr->rom_device; - hwaddr start_addr, size; + hwaddr start_addr, size, slot_size; void *ram; if (!memory_region_is_ram(mr)) { @@ -985,41 +1028,52 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml, kvm_slots_lock(kml); if (!add) { - mem = kvm_lookup_matching_slot(kml, start_addr, size); - if (!mem) { - goto out; - } - if (mem->flags & KVM_MEM_LOG_DIRTY_PAGES) { - kvm_physical_sync_dirty_bitmap(kml, section); - } + do { + slot_size = MIN(kvm_max_slot_size, size); + mem = kvm_lookup_matching_slot(kml, start_addr, slot_size); + if (!mem) { + goto out; + } + if (mem->flags & KVM_MEM_LOG_DIRTY_PAGES) { + kvm_physical_sync_dirty_bitmap(kml, section); + } - /* unregister the slot */ - g_free(mem->dirty_bmap); - mem->dirty_bmap = NULL; - mem->memory_size = 0; - mem->flags = 0; - err = kvm_set_user_memory_region(kml, mem, false); - if (err) { - fprintf(stderr, "%s: error unregistering slot: %s\n", - __func__, strerror(-err)); - abort(); - } + /* unregister the slot */ + g_free(mem->dirty_bmap); + mem->dirty_bmap = NULL; + mem->memory_size = 0; + mem->flags = 0; + err = kvm_set_user_memory_region(kml, mem, false); + if (err) { + fprintf(stderr, "%s: error unregistering slot: %s\n", + __func__, strerror(-err)); + abort(); + } + start_addr += slot_size; + size -= slot_size; + } while (size); goto out; } /* register the new slot */ - mem = kvm_alloc_slot(kml); - mem->memory_size = size; - mem->start_addr = start_addr; - mem->ram = ram; - mem->flags = kvm_mem_flags(mr); - - err = kvm_set_user_memory_region(kml, mem, true); - if (err) { - fprintf(stderr, "%s: error registering slot: %s\n", __func__, - strerror(-err)); - abort(); - } + do { + slot_size = MIN(kvm_max_slot_size, size); + mem = kvm_alloc_slot(kml); + mem->memory_size = slot_size; + mem->start_addr = start_addr; + mem->ram = ram; + mem->flags = kvm_mem_flags(mr); + + err = kvm_set_user_memory_region(kml, mem, true); + if (err) { + fprintf(stderr, "%s: error registering slot: %s\n", __func__, + strerror(-err)); + abort(); + } + start_addr += slot_size; + ram += slot_size; + size -= slot_size; + } while (size); out: kvm_slots_unlock(kml); @@ -2859,6 +2913,7 @@ static bool kvm_accel_has_memory(MachineState *ms, AddressSpace *as, for (i = 0; i < kvm->nr_as; ++i) { if (kvm->as[i].as == as && kvm->as[i].ml) { + size = MIN(kvm_max_slot_size, size); return NULL != kvm_lookup_matching_slot(kvm->as[i].ml, start_addr, size); } diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index abae79650c..defc8d5929 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -33,6 +33,7 @@ #include "exec/helper-proto.h" #include "qemu/atomic.h" #include "qemu/atomic128.h" +#include "translate-all.h" /* DEBUG defines, enable DEBUG_TLB_LOG to log to the CPU_LOG_MMU target */ /* #define DEBUG_TLB */ @@ -577,7 +578,8 @@ static void tlb_reset_dirty_range_locked(CPUTLBEntry *tlb_entry, { uintptr_t addr = tlb_entry->addr_write; - if ((addr & (TLB_INVALID_MASK | TLB_MMIO | TLB_NOTDIRTY)) == 0) { + if ((addr & (TLB_INVALID_MASK | TLB_MMIO | + TLB_DISCARD_WRITE | TLB_NOTDIRTY)) == 0) { addr &= TARGET_PAGE_MASK; addr += tlb_entry->addend; if ((addr - start) < length) { @@ -704,13 +706,14 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr, MemoryRegionSection *section; unsigned int index; target_ulong address; - target_ulong code_address; + target_ulong write_address; uintptr_t addend; CPUTLBEntry *te, tn; hwaddr iotlb, xlat, sz, paddr_page; target_ulong vaddr_page; int asidx = cpu_asidx_from_attrs(cpu, attrs); int wp_flags; + bool is_ram, is_romd; assert_cpu_is_self(cpu); @@ -737,22 +740,48 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr, address |= TLB_INVALID_MASK; } if (attrs.byte_swap) { - /* Force the access through the I/O slow path. */ - address |= TLB_MMIO; + address |= TLB_BSWAP; } - if (!memory_region_is_ram(section->mr) && - !memory_region_is_romd(section->mr)) { - /* IO memory case */ - address |= TLB_MMIO; + + is_ram = memory_region_is_ram(section->mr); + is_romd = memory_region_is_romd(section->mr); + + if (is_ram || is_romd) { + /* RAM and ROMD both have associated host memory. */ + addend = (uintptr_t)memory_region_get_ram_ptr(section->mr) + xlat; + } else { + /* I/O does not; force the host address to NULL. */ addend = 0; + } + + write_address = address; + if (is_ram) { + iotlb = memory_region_get_ram_addr(section->mr) + xlat; + /* + * Computing is_clean is expensive; avoid all that unless + * the page is actually writable. + */ + if (prot & PAGE_WRITE) { + if (section->readonly) { + write_address |= TLB_DISCARD_WRITE; + } else if (cpu_physical_memory_is_clean(iotlb)) { + write_address |= TLB_NOTDIRTY; + } + } } else { - /* TLB_MMIO for rom/romd handled below */ - addend = (uintptr_t)memory_region_get_ram_ptr(section->mr) + xlat; + /* I/O or ROMD */ + iotlb = memory_region_section_get_iotlb(cpu, section) + xlat; + /* + * Writes to romd devices must go through MMIO to enable write. + * Reads to romd devices go through the ram_ptr found above, + * but of course reads to I/O must go through MMIO. + */ + write_address |= TLB_MMIO; + if (!is_romd) { + address = write_address; + } } - code_address = address; - iotlb = memory_region_section_get_iotlb(cpu, section, vaddr_page, - paddr_page, xlat, prot, &address); wp_flags = cpu_watchpoint_address_matches(cpu, vaddr_page, TARGET_PAGE_SIZE); @@ -792,8 +821,8 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr, /* * At this point iotlb contains a physical section number in the lower * TARGET_PAGE_BITS, and either - * + the ram_addr_t of the page base of the target RAM (if NOTDIRTY or ROM) - * + the offset within section->mr of the page base (otherwise) + * + the ram_addr_t of the page base of the target RAM (RAM) + * + the offset within section->mr of the page base (I/O, ROMD) * We subtract the vaddr_page (which is page aligned and thus won't * disturb the low bits) to give an offset which can be added to the * (non-page-aligned) vaddr of the eventual memory access to get @@ -816,24 +845,14 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr, } if (prot & PAGE_EXEC) { - tn.addr_code = code_address; + tn.addr_code = address; } else { tn.addr_code = -1; } tn.addr_write = -1; if (prot & PAGE_WRITE) { - if ((memory_region_is_ram(section->mr) && section->readonly) - || memory_region_is_romd(section->mr)) { - /* Write access calls the I/O callback. */ - tn.addr_write = address | TLB_MMIO; - } else if (memory_region_is_ram(section->mr) - && cpu_physical_memory_is_clean( - memory_region_get_ram_addr(section->mr) + xlat)) { - tn.addr_write = address | TLB_NOTDIRTY; - } else { - tn.addr_write = address; - } + tn.addr_write = write_address; if (prot & PAGE_WRITE_INV) { tn.addr_write |= TLB_INVALID_MASK; } @@ -901,19 +920,14 @@ static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry, bool locked = false; MemTxResult r; - if (iotlbentry->attrs.byte_swap) { - op ^= MO_BSWAP; - } - section = iotlb_to_section(cpu, iotlbentry->addr, iotlbentry->attrs); mr = section->mr; mr_offset = (iotlbentry->addr & TARGET_PAGE_MASK) + addr; cpu->mem_io_pc = retaddr; - if (mr != &io_mem_rom && mr != &io_mem_notdirty && !cpu->can_do_io) { + if (!cpu->can_do_io) { cpu_io_recompile(cpu, retaddr); } - cpu->mem_io_vaddr = addr; cpu->mem_io_access_type = access_type; if (mr->global_locking && !qemu_mutex_iothread_locked()) { @@ -947,17 +961,12 @@ static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry, bool locked = false; MemTxResult r; - if (iotlbentry->attrs.byte_swap) { - op ^= MO_BSWAP; - } - section = iotlb_to_section(cpu, iotlbentry->addr, iotlbentry->attrs); mr = section->mr; mr_offset = (iotlbentry->addr & TARGET_PAGE_MASK) + addr; - if (mr != &io_mem_rom && mr != &io_mem_notdirty && !cpu->can_do_io) { + if (!cpu->can_do_io) { cpu_io_recompile(cpu, retaddr); } - cpu->mem_io_vaddr = addr; cpu->mem_io_pc = retaddr; if (mr->global_locking && !qemu_mutex_iothread_locked()) { @@ -1075,6 +1084,33 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr) return qemu_ram_addr_from_host_nofail(p); } +static void notdirty_write(CPUState *cpu, vaddr mem_vaddr, unsigned size, + CPUIOTLBEntry *iotlbentry, uintptr_t retaddr) +{ + ram_addr_t ram_addr = mem_vaddr + iotlbentry->addr; + + trace_memory_notdirty_write_access(mem_vaddr, ram_addr, size); + + if (!cpu_physical_memory_get_dirty_flag(ram_addr, DIRTY_MEMORY_CODE)) { + struct page_collection *pages + = page_collection_lock(ram_addr, ram_addr + size); + tb_invalidate_phys_page_fast(pages, ram_addr, size, retaddr); + page_collection_unlock(pages); + } + + /* + * Set both VGA and migration bits for simplicity and to remove + * the notdirty callback faster. + */ + cpu_physical_memory_set_dirty_range(ram_addr, size, DIRTY_CLIENTS_NOCODE); + + /* We remove the notdirty callback only if the code has been flushed. */ + if (!cpu_physical_memory_is_clean(ram_addr)) { + trace_memory_notdirty_set_dirty(mem_vaddr); + tlb_set_dirty(cpu, mem_vaddr); + } +} + /* * Probe for whether the specified guest access is permitted. If it is not * permitted then an exception will be taken in the same way as if this @@ -1126,16 +1162,24 @@ void *probe_access(CPUArchState *env, target_ulong addr, int size, return NULL; } - /* Handle watchpoints. */ - if (tlb_addr & TLB_WATCHPOINT) { - cpu_check_watchpoint(env_cpu(env), addr, size, - env_tlb(env)->d[mmu_idx].iotlb[index].attrs, - wp_access, retaddr); - } + if (unlikely(tlb_addr & TLB_FLAGS_MASK)) { + CPUIOTLBEntry *iotlbentry = &env_tlb(env)->d[mmu_idx].iotlb[index]; - if (tlb_addr & (TLB_NOTDIRTY | TLB_MMIO)) { - /* I/O access */ - return NULL; + /* Reject I/O access, or other required slow-path. */ + if (tlb_addr & (TLB_MMIO | TLB_BSWAP | TLB_DISCARD_WRITE)) { + return NULL; + } + + /* Handle watchpoints. */ + if (tlb_addr & TLB_WATCHPOINT) { + cpu_check_watchpoint(env_cpu(env), addr, size, + iotlbentry->attrs, wp_access, retaddr); + } + + /* Handle clean RAM pages. */ + if (tlb_addr & TLB_NOTDIRTY) { + notdirty_write(env_cpu(env), addr, size, iotlbentry, retaddr); + } } return (void *)((uintptr_t)addr + entry->addend); @@ -1194,8 +1238,7 @@ void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr, /* Probe for a read-modify-write atomic operation. Do not allow unaligned * operations, or io operations to proceed. Return the host address. */ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, - TCGMemOpIdx oi, uintptr_t retaddr, - NotDirtyInfo *ndi) + TCGMemOpIdx oi, uintptr_t retaddr) { size_t mmu_idx = get_mmuidx(oi); uintptr_t index = tlb_index(env, mmu_idx, addr); @@ -1255,12 +1298,9 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, hostaddr = (void *)((uintptr_t)addr + tlbe->addend); - ndi->active = false; if (unlikely(tlb_addr & TLB_NOTDIRTY)) { - ndi->active = true; - memory_notdirty_write_prepare(ndi, env_cpu(env), addr, - qemu_ram_addr_from_host_nofail(hostaddr), - 1 << s_bits); + notdirty_write(env_cpu(env), addr, 1 << s_bits, + &env_tlb(env)->d[mmu_idx].iotlb[index], retaddr); } return hostaddr; @@ -1281,7 +1321,30 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, typedef uint64_t FullLoadHelper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uintptr_t retaddr); -static inline uint64_t __attribute__((always_inline)) +static inline uint64_t QEMU_ALWAYS_INLINE +load_memop(const void *haddr, MemOp op) +{ + switch (op) { + case MO_UB: + return ldub_p(haddr); + case MO_BEUW: + return lduw_be_p(haddr); + case MO_LEUW: + return lduw_le_p(haddr); + case MO_BEUL: + return (uint32_t)ldl_be_p(haddr); + case MO_LEUL: + return (uint32_t)ldl_le_p(haddr); + case MO_BEQ: + return ldq_be_p(haddr); + case MO_LEQ: + return ldq_le_p(haddr); + default: + qemu_build_not_reached(); + } +} + +static inline uint64_t QEMU_ALWAYS_INLINE load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uintptr_t retaddr, MemOp op, bool code_read, FullLoadHelper *full_load) @@ -1321,6 +1384,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, /* Handle anything that isn't just a straight memory access. */ if (unlikely(tlb_addr & ~TARGET_PAGE_MASK)) { CPUIOTLBEntry *iotlbentry; + bool need_swap; /* For anything that is unaligned, recurse through full_load. */ if ((addr & (size - 1)) != 0) { @@ -1334,17 +1398,27 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, /* On watchpoint hit, this will longjmp out. */ cpu_check_watchpoint(env_cpu(env), addr, size, iotlbentry->attrs, BP_MEM_READ, retaddr); - - /* The backing page may or may not require I/O. */ - tlb_addr &= ~TLB_WATCHPOINT; - if ((tlb_addr & ~TARGET_PAGE_MASK) == 0) { - goto do_aligned_access; - } } + need_swap = size > 1 && (tlb_addr & TLB_BSWAP); + /* Handle I/O access. */ - return io_readx(env, iotlbentry, mmu_idx, addr, - retaddr, access_type, op); + if (likely(tlb_addr & TLB_MMIO)) { + return io_readx(env, iotlbentry, mmu_idx, addr, retaddr, + access_type, op ^ (need_swap * MO_BSWAP)); + } + + haddr = (void *)((uintptr_t)addr + entry->addend); + + /* + * Keep these two load_memop separate to ensure that the compiler + * is able to fold the entire function to a single instruction. + * There is a build-time assert inside to remind you of this. ;-) + */ + if (unlikely(need_swap)) { + return load_memop(haddr, op ^ MO_BSWAP); + } + return load_memop(haddr, op); } /* Handle slow unaligned access (it spans two pages or IO). */ @@ -1371,35 +1445,8 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, return res & MAKE_64BIT_MASK(0, size * 8); } - do_aligned_access: haddr = (void *)((uintptr_t)addr + entry->addend); - switch (op) { - case MO_UB: - res = ldub_p(haddr); - break; - case MO_BEUW: - res = lduw_be_p(haddr); - break; - case MO_LEUW: - res = lduw_le_p(haddr); - break; - case MO_BEUL: - res = (uint32_t)ldl_be_p(haddr); - break; - case MO_LEUL: - res = (uint32_t)ldl_le_p(haddr); - break; - case MO_BEQ: - res = ldq_be_p(haddr); - break; - case MO_LEQ: - res = ldq_le_p(haddr); - break; - default: - g_assert_not_reached(); - } - - return res; + return load_memop(haddr, op); } /* @@ -1530,7 +1577,37 @@ tcg_target_ulong helper_be_ldsl_mmu(CPUArchState *env, target_ulong addr, * Store Helpers */ -static inline void __attribute__((always_inline)) +static inline void QEMU_ALWAYS_INLINE +store_memop(void *haddr, uint64_t val, MemOp op) +{ + switch (op) { + case MO_UB: + stb_p(haddr, val); + break; + case MO_BEUW: + stw_be_p(haddr, val); + break; + case MO_LEUW: + stw_le_p(haddr, val); + break; + case MO_BEUL: + stl_be_p(haddr, val); + break; + case MO_LEUL: + stl_le_p(haddr, val); + break; + case MO_BEQ: + stq_be_p(haddr, val); + break; + case MO_LEQ: + stq_le_p(haddr, val); + break; + default: + qemu_build_not_reached(); + } +} + +static inline void QEMU_ALWAYS_INLINE store_helper(CPUArchState *env, target_ulong addr, uint64_t val, TCGMemOpIdx oi, uintptr_t retaddr, MemOp op) { @@ -1564,6 +1641,7 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, /* Handle anything that isn't just a straight memory access. */ if (unlikely(tlb_addr & ~TARGET_PAGE_MASK)) { CPUIOTLBEntry *iotlbentry; + bool need_swap; /* For anything that is unaligned, recurse through byte stores. */ if ((addr & (size - 1)) != 0) { @@ -1577,16 +1655,39 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, /* On watchpoint hit, this will longjmp out. */ cpu_check_watchpoint(env_cpu(env), addr, size, iotlbentry->attrs, BP_MEM_WRITE, retaddr); - - /* The backing page may or may not require I/O. */ - tlb_addr &= ~TLB_WATCHPOINT; - if ((tlb_addr & ~TARGET_PAGE_MASK) == 0) { - goto do_aligned_access; - } } + need_swap = size > 1 && (tlb_addr & TLB_BSWAP); + /* Handle I/O access. */ - io_writex(env, iotlbentry, mmu_idx, val, addr, retaddr, op); + if (tlb_addr & TLB_MMIO) { + io_writex(env, iotlbentry, mmu_idx, val, addr, retaddr, + op ^ (need_swap * MO_BSWAP)); + return; + } + + /* Ignore writes to ROM. */ + if (unlikely(tlb_addr & TLB_DISCARD_WRITE)) { + return; + } + + /* Handle clean RAM pages. */ + if (tlb_addr & TLB_NOTDIRTY) { + notdirty_write(env_cpu(env), addr, size, iotlbentry, retaddr); + } + + haddr = (void *)((uintptr_t)addr + entry->addend); + + /* + * Keep these two store_memop separate to ensure that the compiler + * is able to fold the entire function to a single instruction. + * There is a build-time assert inside to remind you of this. ;-) + */ + if (unlikely(need_swap)) { + store_memop(haddr, val, op ^ MO_BSWAP); + } else { + store_memop(haddr, val, op); + } return; } @@ -1655,34 +1756,8 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, return; } - do_aligned_access: haddr = (void *)((uintptr_t)addr + entry->addend); - switch (op) { - case MO_UB: - stb_p(haddr, val); - break; - case MO_BEUW: - stw_be_p(haddr, val); - break; - case MO_LEUW: - stw_le_p(haddr, val); - break; - case MO_BEUL: - stl_be_p(haddr, val); - break; - case MO_LEUL: - stl_le_p(haddr, val); - break; - case MO_BEQ: - stq_be_p(haddr, val); - break; - case MO_LEQ: - stq_le_p(haddr, val); - break; - default: - g_assert_not_reached(); - break; - } + store_memop(haddr, val, op); } void helper_ret_stb_mmu(CPUArchState *env, target_ulong addr, uint8_t val, @@ -1733,14 +1808,9 @@ void helper_be_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val, #define EXTRA_ARGS , TCGMemOpIdx oi, uintptr_t retaddr #define ATOMIC_NAME(X) \ HELPER(glue(glue(glue(atomic_ ## X, SUFFIX), END), _mmu)) -#define ATOMIC_MMU_DECLS NotDirtyInfo ndi -#define ATOMIC_MMU_LOOKUP atomic_mmu_lookup(env, addr, oi, retaddr, &ndi) -#define ATOMIC_MMU_CLEANUP \ - do { \ - if (unlikely(ndi.active)) { \ - memory_notdirty_write_complete(&ndi); \ - } \ - } while (0) +#define ATOMIC_MMU_DECLS +#define ATOMIC_MMU_LOOKUP atomic_mmu_lookup(env, addr, oi, retaddr) +#define ATOMIC_MMU_CLEANUP #define DATA_SIZE 1 #include "atomic_template.h" @@ -1768,7 +1838,7 @@ void helper_be_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val, #undef ATOMIC_MMU_LOOKUP #define EXTRA_ARGS , TCGMemOpIdx oi #define ATOMIC_NAME(X) HELPER(glue(glue(atomic_ ## X, SUFFIX), END)) -#define ATOMIC_MMU_LOOKUP atomic_mmu_lookup(env, addr, oi, GETPC(), &ndi) +#define ATOMIC_MMU_LOOKUP atomic_mmu_lookup(env, addr, oi, GETPC()) #define DATA_SIZE 1 #include "atomic_template.h" diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 5d1e08b169..66d4bc4341 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -1889,7 +1889,7 @@ static void tb_invalidate_phys_page_range__locked(struct page_collection *pages, PageDesc *p, tb_page_addr_t start, tb_page_addr_t end, - int is_cpu_write_access) + uintptr_t retaddr) { TranslationBlock *tb; tb_page_addr_t tb_start, tb_end; @@ -1897,9 +1897,9 @@ tb_invalidate_phys_page_range__locked(struct page_collection *pages, #ifdef TARGET_HAS_PRECISE_SMC CPUState *cpu = current_cpu; CPUArchState *env = NULL; - int current_tb_not_found = is_cpu_write_access; + bool current_tb_not_found = retaddr != 0; + bool current_tb_modified = false; TranslationBlock *current_tb = NULL; - int current_tb_modified = 0; target_ulong current_pc = 0; target_ulong current_cs_base = 0; uint32_t current_flags = 0; @@ -1931,24 +1931,21 @@ tb_invalidate_phys_page_range__locked(struct page_collection *pages, if (!(tb_end <= start || tb_start >= end)) { #ifdef TARGET_HAS_PRECISE_SMC if (current_tb_not_found) { - current_tb_not_found = 0; - current_tb = NULL; - if (cpu->mem_io_pc) { - /* now we have a real cpu fault */ - current_tb = tcg_tb_lookup(cpu->mem_io_pc); - } + current_tb_not_found = false; + /* now we have a real cpu fault */ + current_tb = tcg_tb_lookup(retaddr); } if (current_tb == tb && (tb_cflags(current_tb) & CF_COUNT_MASK) != 1) { - /* If we are modifying the current TB, we must stop - its execution. We could be more precise by checking - that the modification is after the current PC, but it - would require a specialized function to partially - restore the CPU state */ - - current_tb_modified = 1; - cpu_restore_state_from_tb(cpu, current_tb, - cpu->mem_io_pc, true); + /* + * If we are modifying the current TB, we must stop + * its execution. We could be more precise by checking + * that the modification is after the current PC, but it + * would require a specialized function to partially + * restore the CPU state. + */ + current_tb_modified = true; + cpu_restore_state_from_tb(cpu, current_tb, retaddr, true); cpu_get_tb_cpu_state(env, ¤t_pc, ¤t_cs_base, ¤t_flags); } @@ -1983,8 +1980,7 @@ tb_invalidate_phys_page_range__locked(struct page_collection *pages, * * Called with mmap_lock held for user-mode emulation */ -void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, - int is_cpu_write_access) +void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end) { struct page_collection *pages; PageDesc *p; @@ -1996,8 +1992,7 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, return; } pages = page_collection_lock(start, end); - tb_invalidate_phys_page_range__locked(pages, p, start, end, - is_cpu_write_access); + tb_invalidate_phys_page_range__locked(pages, p, start, end, 0); page_collection_unlock(pages); } @@ -2044,7 +2039,8 @@ void tb_invalidate_phys_range(target_ulong start, target_ulong end) * Call with all @pages in the range [@start, @start + len[ locked. */ void tb_invalidate_phys_page_fast(struct page_collection *pages, - tb_page_addr_t start, int len) + tb_page_addr_t start, int len, + uintptr_t retaddr) { PageDesc *p; @@ -2071,7 +2067,8 @@ void tb_invalidate_phys_page_fast(struct page_collection *pages, } } else { do_invalidate: - tb_invalidate_phys_page_range__locked(pages, p, start, start + len, 1); + tb_invalidate_phys_page_range__locked(pages, p, start, start + len, + retaddr); } } #else @@ -2145,16 +2142,16 @@ static bool tb_invalidate_phys_page(tb_page_addr_t addr, uintptr_t pc) #endif /* user-mode: call with mmap_lock held */ -void tb_check_watchpoint(CPUState *cpu) +void tb_check_watchpoint(CPUState *cpu, uintptr_t retaddr) { TranslationBlock *tb; assert_memory_lock(); - tb = tcg_tb_lookup(cpu->mem_io_pc); + tb = tcg_tb_lookup(retaddr); if (tb) { /* We can use retranslation to find the PC. */ - cpu_restore_state_from_tb(cpu, tb, cpu->mem_io_pc, true); + cpu_restore_state_from_tb(cpu, tb, retaddr, true); tb_phys_invalidate(tb, -1); } else { /* The exception probably happened in a helper. The CPU state should diff --git a/accel/tcg/translate-all.h b/accel/tcg/translate-all.h index 64f5fd9a05..a557b4e2bb 100644 --- a/accel/tcg/translate-all.h +++ b/accel/tcg/translate-all.h @@ -27,10 +27,10 @@ struct page_collection *page_collection_lock(tb_page_addr_t start, tb_page_addr_t end); void page_collection_unlock(struct page_collection *set); void tb_invalidate_phys_page_fast(struct page_collection *pages, - tb_page_addr_t start, int len); -void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, - int is_cpu_write_access); -void tb_check_watchpoint(CPUState *cpu); + tb_page_addr_t start, int len, + uintptr_t retaddr); +void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end); +void tb_check_watchpoint(CPUState *cpu, uintptr_t retaddr); #ifdef CONFIG_USER_ONLY int page_unprotect(target_ulong address, uintptr_t pc); diff --git a/block/snapshot.c b/block/snapshot.c index f2f48f926a..8081616ae9 100644 --- a/block/snapshot.c +++ b/block/snapshot.c @@ -31,6 +31,7 @@ #include "qapi/qmp/qerror.h" #include "qapi/qmp/qstring.h" #include "qemu/option.h" +#include "sysemu/block-backend.h" QemuOptsList internal_snapshot_opts = { .name = "snapshot", @@ -384,6 +385,16 @@ int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs, return ret; } +static bool bdrv_all_snapshots_includes_bs(BlockDriverState *bs) +{ + if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) { + return false; + } + + /* Include all nodes that are either in use by a BlockBackend, or that + * aren't attached to any node, but owned by the monitor. */ + return bdrv_has_blk(bs) || QLIST_EMPTY(&bs->parents); +} /* Group operations. All block drivers are involved. * These functions will properly handle dataplane (take aio_context_acquire @@ -399,7 +410,7 @@ bool bdrv_all_can_snapshot(BlockDriverState **first_bad_bs) AioContext *ctx = bdrv_get_aio_context(bs); aio_context_acquire(ctx); - if (bdrv_is_inserted(bs) && !bdrv_is_read_only(bs)) { + if (bdrv_all_snapshots_includes_bs(bs)) { ok = bdrv_can_snapshot(bs); } aio_context_release(ctx); @@ -426,8 +437,9 @@ int bdrv_all_delete_snapshot(const char *name, BlockDriverState **first_bad_bs, AioContext *ctx = bdrv_get_aio_context(bs); aio_context_acquire(ctx); - if (bdrv_can_snapshot(bs) && - bdrv_snapshot_find(bs, snapshot, name) >= 0) { + if (bdrv_all_snapshots_includes_bs(bs) && + bdrv_snapshot_find(bs, snapshot, name) >= 0) + { ret = bdrv_snapshot_delete(bs, snapshot->id_str, snapshot->name, err); } @@ -455,7 +467,7 @@ int bdrv_all_goto_snapshot(const char *name, BlockDriverState **first_bad_bs, AioContext *ctx = bdrv_get_aio_context(bs); aio_context_acquire(ctx); - if (bdrv_can_snapshot(bs)) { + if (bdrv_all_snapshots_includes_bs(bs)) { ret = bdrv_snapshot_goto(bs, name, errp); } aio_context_release(ctx); @@ -481,7 +493,7 @@ int bdrv_all_find_snapshot(const char *name, BlockDriverState **first_bad_bs) AioContext *ctx = bdrv_get_aio_context(bs); aio_context_acquire(ctx); - if (bdrv_can_snapshot(bs)) { + if (bdrv_all_snapshots_includes_bs(bs)) { err = bdrv_snapshot_find(bs, &sn, name); } aio_context_release(ctx); @@ -512,7 +524,7 @@ int bdrv_all_create_snapshot(QEMUSnapshotInfo *sn, if (bs == vm_state_bs) { sn->vm_state_size = vm_state_size; err = bdrv_snapshot_create(bs, sn); - } else if (bdrv_can_snapshot(bs)) { + } else if (bdrv_all_snapshots_includes_bs(bs)) { sn->vm_state_size = 0; err = bdrv_snapshot_create(bs, sn); } @@ -538,7 +550,7 @@ BlockDriverState *bdrv_all_find_vmstate_bs(void) bool found; aio_context_acquire(ctx); - found = bdrv_can_snapshot(bs); + found = bdrv_all_snapshots_includes_bs(bs) && bdrv_can_snapshot(bs); aio_context_release(ctx); if (found) { diff --git a/blockdev-nbd.c b/blockdev-nbd.c index 213f226ac1..6a8b206e1d 100644 --- a/blockdev-nbd.c +++ b/blockdev-nbd.c @@ -151,6 +151,7 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name, BlockBackend *on_eject_blk; NBDExport *exp; int64_t len; + AioContext *aio_context; if (!nbd_server) { error_setg(errp, "NBD server not running"); @@ -173,11 +174,13 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name, return; } + aio_context = bdrv_get_aio_context(bs); + aio_context_acquire(aio_context); len = bdrv_getlength(bs); if (len < 0) { error_setg_errno(errp, -len, "Failed to determine the NBD export's length"); - return; + goto out; } if (!has_writable) { @@ -190,13 +193,16 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name, exp = nbd_export_new(bs, 0, len, name, NULL, bitmap, !writable, !writable, NULL, false, on_eject_blk, errp); if (!exp) { - return; + goto out; } /* The list of named exports has a strong reference to this export now and * our only way of accessing it is through nbd_export_find(), so we can drop * the strong reference that is @exp. */ nbd_export_put(exp); + + out: + aio_context_release(aio_context); } void qmp_nbd_server_remove(const char *name, @@ -204,6 +210,7 @@ void qmp_nbd_server_remove(const char *name, Error **errp) { NBDExport *exp; + AioContext *aio_context; if (!nbd_server) { error_setg(errp, "NBD server not running"); @@ -220,7 +227,10 @@ void qmp_nbd_server_remove(const char *name, mode = NBD_SERVER_REMOVE_MODE_SAFE; } + aio_context = nbd_export_aio_context(exp); + aio_context_acquire(aio_context); nbd_export_remove(exp, mode, errp); + aio_context_release(aio_context); } void qmp_nbd_server_stop(Error **errp) @@ -728,7 +728,7 @@ ARCH= # Normalise host CPU name and set ARCH. # Note that this case should only have supported host CPUs, not guests. case "$cpu" in - ppc|ppc64|s390|s390x|sparc64|x32|riscv32|riscv64) + ppc|ppc64|s390x|sparc64|x32|riscv32|riscv64) supported_cpu="yes" ;; ppc64le) @@ -6166,9 +6166,6 @@ if { test "$cpu" = "i386" || test "$cpu" = "x86_64"; } && \ fi done fi -if test "$ARCH" = "ppc64" && test "$targetos" != "Darwin" ; then - roms="$roms spapr-rtas" -fi # Only build s390-ccw bios if we're on s390x and the compiler has -march=z900 if test "$cpu" = "s390x" ; then @@ -7302,6 +7299,7 @@ echo "OBJCOPY=$objcopy" >> $config_host_mak echo "LD=$ld" >> $config_host_mak echo "RANLIB=$ranlib" >> $config_host_mak echo "NM=$nm" >> $config_host_mak +echo "PKG_CONFIG=$pkg_config_exe" >> $config_host_mak echo "WINDRES=$windres" >> $config_host_mak echo "CFLAGS=$CFLAGS" >> $config_host_mak echo "CFLAGS_NOPIE=$CFLAGS_NOPIE" >> $config_host_mak @@ -7799,13 +7797,12 @@ fi DIRS="tests tests/tcg tests/tcg/lm32 tests/libqos tests/qapi-schema tests/qemu-iotests tests/vm" DIRS="$DIRS tests/fp tests/qgraph" DIRS="$DIRS docs docs/interop fsdev scsi" -DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas pc-bios/s390-ccw" +DIRS="$DIRS pc-bios/optionrom pc-bios/s390-ccw" DIRS="$DIRS roms/seabios roms/vgabios" LINKS="Makefile" LINKS="$LINKS tests/tcg/lm32/Makefile po/Makefile" LINKS="$LINKS tests/tcg/Makefile.target tests/fp/Makefile" LINKS="$LINKS pc-bios/optionrom/Makefile pc-bios/keymaps" -LINKS="$LINKS pc-bios/spapr-rtas/Makefile" LINKS="$LINKS pc-bios/s390-ccw/Makefile" LINKS="$LINKS roms/seabios/Makefile roms/vgabios/Makefile" LINKS="$LINKS pc-bios/qemu-icon.bmp" diff --git a/crypto/block-luks.c b/crypto/block-luks.c index 743949adbf..4861db810c 100644 --- a/crypto/block-luks.c +++ b/crypto/block-luks.c @@ -143,7 +143,7 @@ struct QCryptoBlockLUKSKeySlot { /* salt for PBKDF2 */ uint8_t salt[QCRYPTO_BLOCK_LUKS_SALT_LEN]; /* start sector of key material */ - uint32_t key_offset; + uint32_t key_offset_sector; /* number of anti-forensic stripes */ uint32_t stripes; }; @@ -172,10 +172,10 @@ struct QCryptoBlockLUKSHeader { char hash_spec[QCRYPTO_BLOCK_LUKS_HASH_SPEC_LEN]; /* start offset of the volume data (in 512 byte sectors) */ - uint32_t payload_offset; + uint32_t payload_offset_sector; /* Number of key bytes */ - uint32_t key_bytes; + uint32_t master_key_len; /* master key checksum after PBKDF2 */ uint8_t master_key_digest[QCRYPTO_BLOCK_LUKS_DIGEST_LEN]; @@ -199,13 +199,25 @@ QEMU_BUILD_BUG_ON(sizeof(struct QCryptoBlockLUKSHeader) != 592); struct QCryptoBlockLUKS { QCryptoBlockLUKSHeader header; - /* Cache parsed versions of what's in header fields, - * as we can't rely on QCryptoBlock.cipher being - * non-NULL */ + /* Main encryption algorithm used for encryption*/ QCryptoCipherAlgorithm cipher_alg; + + /* Mode of encryption for the selected encryption algorithm */ QCryptoCipherMode cipher_mode; + + /* Initialization vector generation algorithm */ QCryptoIVGenAlgorithm ivgen_alg; + + /* Hash algorithm used for IV generation*/ QCryptoHashAlgorithm ivgen_hash_alg; + + /* + * Encryption algorithm used for IV generation. + * Usually the same as main encryption algorithm + */ + QCryptoCipherAlgorithm ivgen_cipher_alg; + + /* Hash algorithm used in pbkdf2 function */ QCryptoHashAlgorithm hash_alg; }; @@ -398,6 +410,466 @@ qcrypto_block_luks_essiv_cipher(QCryptoCipherAlgorithm cipher, } /* + * Returns number of sectors needed to store the key material + * given number of anti forensic stripes + */ +static int +qcrypto_block_luks_splitkeylen_sectors(const QCryptoBlockLUKS *luks, + unsigned int header_sectors, + unsigned int stripes) +{ + /* + * This calculation doesn't match that shown in the spec, + * but instead follows the cryptsetup implementation. + */ + + size_t splitkeylen = luks->header.master_key_len * stripes; + + /* First align the key material size to block size*/ + size_t splitkeylen_sectors = + DIV_ROUND_UP(splitkeylen, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE); + + /* Then also align the key material size to the size of the header */ + return ROUND_UP(splitkeylen_sectors, header_sectors); +} + +/* + * Stores the main LUKS header, taking care of endianess + */ +static int +qcrypto_block_luks_store_header(QCryptoBlock *block, + QCryptoBlockWriteFunc writefunc, + void *opaque, + Error **errp) +{ + const QCryptoBlockLUKS *luks = block->opaque; + Error *local_err = NULL; + size_t i; + g_autofree QCryptoBlockLUKSHeader *hdr_copy = NULL; + + /* Create a copy of the header */ + hdr_copy = g_new0(QCryptoBlockLUKSHeader, 1); + memcpy(hdr_copy, &luks->header, sizeof(QCryptoBlockLUKSHeader)); + + /* + * Everything on disk uses Big Endian (tm), so flip header fields + * before writing them + */ + cpu_to_be16s(&hdr_copy->version); + cpu_to_be32s(&hdr_copy->payload_offset_sector); + cpu_to_be32s(&hdr_copy->master_key_len); + cpu_to_be32s(&hdr_copy->master_key_iterations); + + for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { + cpu_to_be32s(&hdr_copy->key_slots[i].active); + cpu_to_be32s(&hdr_copy->key_slots[i].iterations); + cpu_to_be32s(&hdr_copy->key_slots[i].key_offset_sector); + cpu_to_be32s(&hdr_copy->key_slots[i].stripes); + } + + /* Write out the partition header and key slot headers */ + writefunc(block, 0, (const uint8_t *)hdr_copy, sizeof(*hdr_copy), + opaque, &local_err); + + if (local_err) { + error_propagate(errp, local_err); + return -1; + } + return 0; +} + +/* + * Loads the main LUKS header,and byteswaps it to native endianess + * And run basic sanity checks on it + */ +static int +qcrypto_block_luks_load_header(QCryptoBlock *block, + QCryptoBlockReadFunc readfunc, + void *opaque, + Error **errp) +{ + ssize_t rv; + size_t i; + QCryptoBlockLUKS *luks = block->opaque; + + /* + * Read the entire LUKS header, minus the key material from + * the underlying device + */ + rv = readfunc(block, 0, + (uint8_t *)&luks->header, + sizeof(luks->header), + opaque, + errp); + if (rv < 0) { + return rv; + } + + /* + * The header is always stored in big-endian format, so + * convert everything to native + */ + be16_to_cpus(&luks->header.version); + be32_to_cpus(&luks->header.payload_offset_sector); + be32_to_cpus(&luks->header.master_key_len); + be32_to_cpus(&luks->header.master_key_iterations); + + for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { + be32_to_cpus(&luks->header.key_slots[i].active); + be32_to_cpus(&luks->header.key_slots[i].iterations); + be32_to_cpus(&luks->header.key_slots[i].key_offset_sector); + be32_to_cpus(&luks->header.key_slots[i].stripes); + } + + return 0; +} + +/* + * Does basic sanity checks on the LUKS header + */ +static int +qcrypto_block_luks_check_header(const QCryptoBlockLUKS *luks, Error **errp) +{ + size_t i, j; + + unsigned int header_sectors = QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET / + QCRYPTO_BLOCK_LUKS_SECTOR_SIZE; + + if (memcmp(luks->header.magic, qcrypto_block_luks_magic, + QCRYPTO_BLOCK_LUKS_MAGIC_LEN) != 0) { + error_setg(errp, "Volume is not in LUKS format"); + return -1; + } + + if (luks->header.version != QCRYPTO_BLOCK_LUKS_VERSION) { + error_setg(errp, "LUKS version %" PRIu32 " is not supported", + luks->header.version); + return -1; + } + + /* Check all keyslots for corruption */ + for (i = 0 ; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS ; i++) { + + const QCryptoBlockLUKSKeySlot *slot1 = &luks->header.key_slots[i]; + unsigned int start1 = slot1->key_offset_sector; + unsigned int len1 = + qcrypto_block_luks_splitkeylen_sectors(luks, + header_sectors, + slot1->stripes); + + if (slot1->stripes == 0) { + error_setg(errp, "Keyslot %zu is corrupted (stripes == 0)", i); + return -1; + } + + if (slot1->active != QCRYPTO_BLOCK_LUKS_KEY_SLOT_DISABLED && + slot1->active != QCRYPTO_BLOCK_LUKS_KEY_SLOT_ENABLED) { + error_setg(errp, + "Keyslot %zu state (active/disable) is corrupted", i); + return -1; + } + + if (start1 + len1 > luks->header.payload_offset_sector) { + error_setg(errp, + "Keyslot %zu is overlapping with the encrypted payload", + i); + return -1; + } + + for (j = i + 1 ; j < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS ; j++) { + const QCryptoBlockLUKSKeySlot *slot2 = &luks->header.key_slots[j]; + unsigned int start2 = slot2->key_offset_sector; + unsigned int len2 = + qcrypto_block_luks_splitkeylen_sectors(luks, + header_sectors, + slot2->stripes); + + if (start1 + len1 > start2 && start2 + len2 > start1) { + error_setg(errp, + "Keyslots %zu and %zu are overlapping in the header", + i, j); + return -1; + } + } + + } + return 0; +} + +/* + * Parses the crypto parameters that are stored in the LUKS header + */ + +static int +qcrypto_block_luks_parse_header(QCryptoBlockLUKS *luks, Error **errp) +{ + g_autofree char *cipher_mode = g_strdup(luks->header.cipher_mode); + char *ivgen_name, *ivhash_name; + Error *local_err = NULL; + + /* + * The cipher_mode header contains a string that we have + * to further parse, of the format + * + * <cipher-mode>-<iv-generator>[:<iv-hash>] + * + * eg cbc-essiv:sha256, cbc-plain64 + */ + ivgen_name = strchr(cipher_mode, '-'); + if (!ivgen_name) { + error_setg(errp, "Unexpected cipher mode string format %s", + luks->header.cipher_mode); + return -1; + } + *ivgen_name = '\0'; + ivgen_name++; + + ivhash_name = strchr(ivgen_name, ':'); + if (!ivhash_name) { + luks->ivgen_hash_alg = 0; + } else { + *ivhash_name = '\0'; + ivhash_name++; + + luks->ivgen_hash_alg = qcrypto_block_luks_hash_name_lookup(ivhash_name, + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return -1; + } + } + + luks->cipher_mode = qcrypto_block_luks_cipher_mode_lookup(cipher_mode, + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return -1; + } + + luks->cipher_alg = + qcrypto_block_luks_cipher_name_lookup(luks->header.cipher_name, + luks->cipher_mode, + luks->header.master_key_len, + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return -1; + } + + luks->hash_alg = + qcrypto_block_luks_hash_name_lookup(luks->header.hash_spec, + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return -1; + } + + luks->ivgen_alg = qcrypto_block_luks_ivgen_name_lookup(ivgen_name, + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return -1; + } + + if (luks->ivgen_alg == QCRYPTO_IVGEN_ALG_ESSIV) { + if (!ivhash_name) { + error_setg(errp, "Missing IV generator hash specification"); + return -1; + } + luks->ivgen_cipher_alg = + qcrypto_block_luks_essiv_cipher(luks->cipher_alg, + luks->ivgen_hash_alg, + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return -1; + } + } else { + + /* + * Note we parsed the ivhash_name earlier in the cipher_mode + * spec string even with plain/plain64 ivgens, but we + * will ignore it, since it is irrelevant for these ivgens. + * This is for compat with dm-crypt which will silently + * ignore hash names with these ivgens rather than report + * an error about the invalid usage + */ + luks->ivgen_cipher_alg = luks->cipher_alg; + } + return 0; +} + +/* + * Given a key slot, user password, and the master key, + * will store the encrypted master key there, and update the + * in-memory header. User must then write the in-memory header + * + * Returns: + * 0 if the keyslot was written successfully + * with the provided password + * -1 if a fatal error occurred while storing the key + */ +static int +qcrypto_block_luks_store_key(QCryptoBlock *block, + unsigned int slot_idx, + const char *password, + uint8_t *masterkey, + uint64_t iter_time, + QCryptoBlockWriteFunc writefunc, + void *opaque, + Error **errp) +{ + QCryptoBlockLUKS *luks = block->opaque; + QCryptoBlockLUKSKeySlot *slot = &luks->header.key_slots[slot_idx]; + g_autofree uint8_t *splitkey = NULL; + size_t splitkeylen; + g_autofree uint8_t *slotkey = NULL; + g_autoptr(QCryptoCipher) cipher = NULL; + g_autoptr(QCryptoIVGen) ivgen = NULL; + Error *local_err = NULL; + uint64_t iters; + int ret = -1; + + if (qcrypto_random_bytes(slot->salt, + QCRYPTO_BLOCK_LUKS_SALT_LEN, + errp) < 0) { + goto cleanup; + } + + splitkeylen = luks->header.master_key_len * slot->stripes; + + /* + * Determine how many iterations are required to + * hash the user password while consuming 1 second of compute + * time + */ + iters = qcrypto_pbkdf2_count_iters(luks->hash_alg, + (uint8_t *)password, strlen(password), + slot->salt, + QCRYPTO_BLOCK_LUKS_SALT_LEN, + luks->header.master_key_len, + &local_err); + if (local_err) { + error_propagate(errp, local_err); + goto cleanup; + } + + if (iters > (ULLONG_MAX / iter_time)) { + error_setg_errno(errp, ERANGE, + "PBKDF iterations %llu too large to scale", + (unsigned long long)iters); + goto cleanup; + } + + /* iter_time was in millis, but count_iters reported for secs */ + iters = iters * iter_time / 1000; + + if (iters > UINT32_MAX) { + error_setg_errno(errp, ERANGE, + "PBKDF iterations %llu larger than %u", + (unsigned long long)iters, UINT32_MAX); + goto cleanup; + } + + slot->iterations = + MAX(iters, QCRYPTO_BLOCK_LUKS_MIN_SLOT_KEY_ITERS); + + + /* + * Generate a key that we'll use to encrypt the master + * key, from the user's password + */ + slotkey = g_new0(uint8_t, luks->header.master_key_len); + if (qcrypto_pbkdf2(luks->hash_alg, + (uint8_t *)password, strlen(password), + slot->salt, + QCRYPTO_BLOCK_LUKS_SALT_LEN, + slot->iterations, + slotkey, luks->header.master_key_len, + errp) < 0) { + goto cleanup; + } + + + /* + * Setup the encryption objects needed to encrypt the + * master key material + */ + cipher = qcrypto_cipher_new(luks->cipher_alg, + luks->cipher_mode, + slotkey, luks->header.master_key_len, + errp); + if (!cipher) { + goto cleanup; + } + + ivgen = qcrypto_ivgen_new(luks->ivgen_alg, + luks->ivgen_cipher_alg, + luks->ivgen_hash_alg, + slotkey, luks->header.master_key_len, + errp); + if (!ivgen) { + goto cleanup; + } + + /* + * Before storing the master key, we need to vastly + * increase its size, as protection against forensic + * disk data recovery + */ + splitkey = g_new0(uint8_t, splitkeylen); + + if (qcrypto_afsplit_encode(luks->hash_alg, + luks->header.master_key_len, + slot->stripes, + masterkey, + splitkey, + errp) < 0) { + goto cleanup; + } + + /* + * Now we encrypt the split master key with the key generated + * from the user's password, before storing it + */ + if (qcrypto_block_cipher_encrypt_helper(cipher, block->niv, ivgen, + QCRYPTO_BLOCK_LUKS_SECTOR_SIZE, + 0, + splitkey, + splitkeylen, + errp) < 0) { + goto cleanup; + } + + /* Write out the slot's master key material. */ + if (writefunc(block, + slot->key_offset_sector * + QCRYPTO_BLOCK_LUKS_SECTOR_SIZE, + splitkey, splitkeylen, + opaque, + errp) != splitkeylen) { + goto cleanup; + } + + slot->active = QCRYPTO_BLOCK_LUKS_KEY_SLOT_ENABLED; + + if (qcrypto_block_luks_store_header(block, writefunc, opaque, errp) < 0) { + goto cleanup; + } + + ret = 0; + +cleanup: + if (slotkey) { + memset(slotkey, 0, luks->header.master_key_len); + } + if (splitkey) { + memset(splitkey, 0, splitkeylen); + } + return ret; +} + +/* * Given a key slot, and user password, this will attempt to unlock * the master encryption key from the key slot. * @@ -410,21 +882,15 @@ qcrypto_block_luks_essiv_cipher(QCryptoCipherAlgorithm cipher, */ static int qcrypto_block_luks_load_key(QCryptoBlock *block, - QCryptoBlockLUKSKeySlot *slot, + size_t slot_idx, const char *password, - QCryptoCipherAlgorithm cipheralg, - QCryptoCipherMode ciphermode, - QCryptoHashAlgorithm hash, - QCryptoIVGenAlgorithm ivalg, - QCryptoCipherAlgorithm ivcipheralg, - QCryptoHashAlgorithm ivhash, uint8_t *masterkey, - size_t masterkeylen, QCryptoBlockReadFunc readfunc, void *opaque, Error **errp) { QCryptoBlockLUKS *luks = block->opaque; + const QCryptoBlockLUKSKeySlot *slot = &luks->header.key_slots[slot_idx]; g_autofree uint8_t *splitkey = NULL; size_t splitkeylen; g_autofree uint8_t *possiblekey = NULL; @@ -438,9 +904,9 @@ qcrypto_block_luks_load_key(QCryptoBlock *block, return 0; } - splitkeylen = masterkeylen * slot->stripes; + splitkeylen = luks->header.master_key_len * slot->stripes; splitkey = g_new0(uint8_t, splitkeylen); - possiblekey = g_new0(uint8_t, masterkeylen); + possiblekey = g_new0(uint8_t, luks->header.master_key_len); /* * The user password is used to generate a (possible) @@ -449,11 +915,11 @@ qcrypto_block_luks_load_key(QCryptoBlock *block, * the key is correct and validate the results of * decryption later. */ - if (qcrypto_pbkdf2(hash, + if (qcrypto_pbkdf2(luks->hash_alg, (const uint8_t *)password, strlen(password), slot->salt, QCRYPTO_BLOCK_LUKS_SALT_LEN, slot->iterations, - possiblekey, masterkeylen, + possiblekey, luks->header.master_key_len, errp) < 0) { return -1; } @@ -466,7 +932,7 @@ qcrypto_block_luks_load_key(QCryptoBlock *block, * then encrypted. */ rv = readfunc(block, - slot->key_offset * QCRYPTO_BLOCK_LUKS_SECTOR_SIZE, + slot->key_offset_sector * QCRYPTO_BLOCK_LUKS_SECTOR_SIZE, splitkey, splitkeylen, opaque, errp); @@ -477,19 +943,23 @@ qcrypto_block_luks_load_key(QCryptoBlock *block, /* Setup the cipher/ivgen that we'll use to try to decrypt * the split master key material */ - cipher = qcrypto_cipher_new(cipheralg, ciphermode, - possiblekey, masterkeylen, + cipher = qcrypto_cipher_new(luks->cipher_alg, + luks->cipher_mode, + possiblekey, + luks->header.master_key_len, errp); if (!cipher) { return -1; } - niv = qcrypto_cipher_get_iv_len(cipheralg, - ciphermode); - ivgen = qcrypto_ivgen_new(ivalg, - ivcipheralg, - ivhash, - possiblekey, masterkeylen, + niv = qcrypto_cipher_get_iv_len(luks->cipher_alg, + luks->cipher_mode); + + ivgen = qcrypto_ivgen_new(luks->ivgen_alg, + luks->ivgen_cipher_alg, + luks->ivgen_hash_alg, + possiblekey, + luks->header.master_key_len, errp); if (!ivgen) { return -1; @@ -518,8 +988,8 @@ qcrypto_block_luks_load_key(QCryptoBlock *block, * Now we've decrypted the split master key, join * it back together to get the actual master key. */ - if (qcrypto_afsplit_decode(hash, - masterkeylen, + if (qcrypto_afsplit_decode(luks->hash_alg, + luks->header.master_key_len, slot->stripes, splitkey, masterkey, @@ -536,12 +1006,14 @@ qcrypto_block_luks_load_key(QCryptoBlock *block, * then comparing that to the hash stored in the key slot * header */ - if (qcrypto_pbkdf2(hash, - masterkey, masterkeylen, + if (qcrypto_pbkdf2(luks->hash_alg, + masterkey, + luks->header.master_key_len, luks->header.master_key_salt, QCRYPTO_BLOCK_LUKS_SALT_LEN, luks->header.master_key_iterations, - keydigest, G_N_ELEMENTS(keydigest), + keydigest, + G_N_ELEMENTS(keydigest), errp) < 0) { return -1; } @@ -568,37 +1040,19 @@ qcrypto_block_luks_load_key(QCryptoBlock *block, static int qcrypto_block_luks_find_key(QCryptoBlock *block, const char *password, - QCryptoCipherAlgorithm cipheralg, - QCryptoCipherMode ciphermode, - QCryptoHashAlgorithm hash, - QCryptoIVGenAlgorithm ivalg, - QCryptoCipherAlgorithm ivcipheralg, - QCryptoHashAlgorithm ivhash, - uint8_t **masterkey, - size_t *masterkeylen, + uint8_t *masterkey, QCryptoBlockReadFunc readfunc, void *opaque, Error **errp) { - QCryptoBlockLUKS *luks = block->opaque; size_t i; int rv; - *masterkey = g_new0(uint8_t, luks->header.key_bytes); - *masterkeylen = luks->header.key_bytes; - for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { rv = qcrypto_block_luks_load_key(block, - &luks->header.key_slots[i], + i, password, - cipheralg, - ciphermode, - hash, - ivalg, - ivcipheralg, - ivhash, - *masterkey, - *masterkeylen, + masterkey, readfunc, opaque, errp); @@ -611,11 +1065,7 @@ qcrypto_block_luks_find_key(QCryptoBlock *block, } error_setg(errp, "Invalid password, cannot unlock any keyslot"); - error: - g_free(*masterkey); - *masterkey = NULL; - *masterkeylen = 0; return -1; } @@ -630,20 +1080,8 @@ qcrypto_block_luks_open(QCryptoBlock *block, size_t n_threads, Error **errp) { - QCryptoBlockLUKS *luks; - Error *local_err = NULL; - int ret = 0; - size_t i; - ssize_t rv; + QCryptoBlockLUKS *luks = NULL; g_autofree uint8_t *masterkey = NULL; - size_t masterkeylen; - char *ivgen_name, *ivhash_name; - QCryptoCipherMode ciphermode; - QCryptoCipherAlgorithm cipheralg; - QCryptoIVGenAlgorithm ivalg; - QCryptoCipherAlgorithm ivcipheralg; - QCryptoHashAlgorithm hash; - QCryptoHashAlgorithm ivhash; g_autofree char *password = NULL; if (!(flags & QCRYPTO_BLOCK_OPEN_NO_IO)) { @@ -662,198 +1100,72 @@ qcrypto_block_luks_open(QCryptoBlock *block, luks = g_new0(QCryptoBlockLUKS, 1); block->opaque = luks; - /* Read the entire LUKS header, minus the key material from - * the underlying device */ - rv = readfunc(block, 0, - (uint8_t *)&luks->header, - sizeof(luks->header), - opaque, - errp); - if (rv < 0) { - ret = rv; - goto fail; - } - - /* The header is always stored in big-endian format, so - * convert everything to native */ - be16_to_cpus(&luks->header.version); - be32_to_cpus(&luks->header.payload_offset); - be32_to_cpus(&luks->header.key_bytes); - be32_to_cpus(&luks->header.master_key_iterations); - - for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { - be32_to_cpus(&luks->header.key_slots[i].active); - be32_to_cpus(&luks->header.key_slots[i].iterations); - be32_to_cpus(&luks->header.key_slots[i].key_offset); - be32_to_cpus(&luks->header.key_slots[i].stripes); - } - - if (memcmp(luks->header.magic, qcrypto_block_luks_magic, - QCRYPTO_BLOCK_LUKS_MAGIC_LEN) != 0) { - error_setg(errp, "Volume is not in LUKS format"); - ret = -EINVAL; - goto fail; - } - if (luks->header.version != QCRYPTO_BLOCK_LUKS_VERSION) { - error_setg(errp, "LUKS version %" PRIu32 " is not supported", - luks->header.version); - ret = -ENOTSUP; - goto fail; - } - - /* - * The cipher_mode header contains a string that we have - * to further parse, of the format - * - * <cipher-mode>-<iv-generator>[:<iv-hash>] - * - * eg cbc-essiv:sha256, cbc-plain64 - */ - ivgen_name = strchr(luks->header.cipher_mode, '-'); - if (!ivgen_name) { - ret = -EINVAL; - error_setg(errp, "Unexpected cipher mode string format %s", - luks->header.cipher_mode); - goto fail; - } - *ivgen_name = '\0'; - ivgen_name++; - - ivhash_name = strchr(ivgen_name, ':'); - if (!ivhash_name) { - ivhash = 0; - } else { - *ivhash_name = '\0'; - ivhash_name++; - - ivhash = qcrypto_block_luks_hash_name_lookup(ivhash_name, - &local_err); - if (local_err) { - ret = -ENOTSUP; - error_propagate(errp, local_err); - goto fail; - } - } - - ciphermode = qcrypto_block_luks_cipher_mode_lookup(luks->header.cipher_mode, - &local_err); - if (local_err) { - ret = -ENOTSUP; - error_propagate(errp, local_err); - goto fail; - } - - cipheralg = qcrypto_block_luks_cipher_name_lookup(luks->header.cipher_name, - ciphermode, - luks->header.key_bytes, - &local_err); - if (local_err) { - ret = -ENOTSUP; - error_propagate(errp, local_err); + if (qcrypto_block_luks_load_header(block, readfunc, opaque, errp) < 0) { goto fail; } - hash = qcrypto_block_luks_hash_name_lookup(luks->header.hash_spec, - &local_err); - if (local_err) { - ret = -ENOTSUP; - error_propagate(errp, local_err); + if (qcrypto_block_luks_check_header(luks, errp) < 0) { goto fail; } - ivalg = qcrypto_block_luks_ivgen_name_lookup(ivgen_name, - &local_err); - if (local_err) { - ret = -ENOTSUP; - error_propagate(errp, local_err); + if (qcrypto_block_luks_parse_header(luks, errp) < 0) { goto fail; } - if (ivalg == QCRYPTO_IVGEN_ALG_ESSIV) { - if (!ivhash_name) { - ret = -EINVAL; - error_setg(errp, "Missing IV generator hash specification"); - goto fail; - } - ivcipheralg = qcrypto_block_luks_essiv_cipher(cipheralg, - ivhash, - &local_err); - if (local_err) { - ret = -ENOTSUP; - error_propagate(errp, local_err); - goto fail; - } - } else { - /* Note we parsed the ivhash_name earlier in the cipher_mode - * spec string even with plain/plain64 ivgens, but we - * will ignore it, since it is irrelevant for these ivgens. - * This is for compat with dm-crypt which will silently - * ignore hash names with these ivgens rather than report - * an error about the invalid usage - */ - ivcipheralg = cipheralg; - } - if (!(flags & QCRYPTO_BLOCK_OPEN_NO_IO)) { /* Try to find which key slot our password is valid for * and unlock the master key from that slot. */ + + masterkey = g_new0(uint8_t, luks->header.master_key_len); + if (qcrypto_block_luks_find_key(block, password, - cipheralg, ciphermode, - hash, - ivalg, - ivcipheralg, - ivhash, - &masterkey, &masterkeylen, + masterkey, readfunc, opaque, errp) < 0) { - ret = -EACCES; goto fail; } /* We have a valid master key now, so can setup the * block device payload decryption objects */ - block->kdfhash = hash; - block->niv = qcrypto_cipher_get_iv_len(cipheralg, - ciphermode); - block->ivgen = qcrypto_ivgen_new(ivalg, - ivcipheralg, - ivhash, - masterkey, masterkeylen, + block->kdfhash = luks->hash_alg; + block->niv = qcrypto_cipher_get_iv_len(luks->cipher_alg, + luks->cipher_mode); + + block->ivgen = qcrypto_ivgen_new(luks->ivgen_alg, + luks->ivgen_cipher_alg, + luks->ivgen_hash_alg, + masterkey, + luks->header.master_key_len, errp); if (!block->ivgen) { - ret = -ENOTSUP; goto fail; } - ret = qcrypto_block_init_cipher(block, cipheralg, ciphermode, - masterkey, masterkeylen, n_threads, - errp); - if (ret < 0) { - ret = -ENOTSUP; + if (qcrypto_block_init_cipher(block, + luks->cipher_alg, + luks->cipher_mode, + masterkey, + luks->header.master_key_len, + n_threads, + errp) < 0) { goto fail; } } block->sector_size = QCRYPTO_BLOCK_LUKS_SECTOR_SIZE; - block->payload_offset = luks->header.payload_offset * + block->payload_offset = luks->header.payload_offset_sector * block->sector_size; - luks->cipher_alg = cipheralg; - luks->cipher_mode = ciphermode; - luks->ivgen_alg = ivalg; - luks->ivgen_hash_alg = ivhash; - luks->hash_alg = hash; - return 0; fail: qcrypto_block_free_cipher(block); qcrypto_ivgen_free(block->ivgen); g_free(luks); - return ret; + return -1; } @@ -878,12 +1190,9 @@ qcrypto_block_luks_create(QCryptoBlock *block, QCryptoBlockCreateOptionsLUKS luks_opts; Error *local_err = NULL; g_autofree uint8_t *masterkey = NULL; - g_autofree uint8_t *slotkey = NULL; - g_autofree uint8_t *splitkey = NULL; - size_t splitkeylen = 0; + size_t header_sectors; + size_t split_key_sectors; size_t i; - g_autoptr(QCryptoCipher) cipher = NULL; - g_autoptr(QCryptoIVGen) ivgen = NULL; g_autofree char *password = NULL; const char *cipher_alg; const char *cipher_mode; @@ -891,7 +1200,6 @@ qcrypto_block_luks_create(QCryptoBlock *block, const char *ivgen_hash_alg = NULL; const char *hash_alg; g_autofree char *cipher_mode_spec = NULL; - QCryptoCipherAlgorithm ivcipheralg = 0; uint64_t iters; memcpy(&luks_opts, &options->u.luks, sizeof(luks_opts)); @@ -916,6 +1224,17 @@ qcrypto_block_luks_create(QCryptoBlock *block, luks_opts.has_ivgen_hash_alg = true; } } + + luks = g_new0(QCryptoBlockLUKS, 1); + block->opaque = luks; + + luks->cipher_alg = luks_opts.cipher_alg; + luks->cipher_mode = luks_opts.cipher_mode; + luks->ivgen_alg = luks_opts.ivgen_alg; + luks->ivgen_hash_alg = luks_opts.ivgen_hash_alg; + luks->hash_alg = luks_opts.hash_alg; + + /* Note we're allowing ivgen_hash_alg to be set even for * non-essiv iv generators that don't need a hash. It will * be silently ignored, for compatibility with dm-crypt */ @@ -923,15 +1242,13 @@ qcrypto_block_luks_create(QCryptoBlock *block, if (!options->u.luks.key_secret) { error_setg(errp, "Parameter '%skey-secret' is required for cipher", optprefix ? optprefix : ""); - return -1; + goto error; } password = qcrypto_secret_lookup_as_utf8(luks_opts.key_secret, errp); if (!password) { - return -1; + goto error; } - luks = g_new0(QCryptoBlockLUKS, 1); - block->opaque = luks; memcpy(luks->header.magic, qcrypto_block_luks_magic, QCRYPTO_BLOCK_LUKS_MAGIC_LEN); @@ -978,24 +1295,27 @@ qcrypto_block_luks_create(QCryptoBlock *block, } if (luks_opts.ivgen_alg == QCRYPTO_IVGEN_ALG_ESSIV) { - ivcipheralg = qcrypto_block_luks_essiv_cipher(luks_opts.cipher_alg, - luks_opts.ivgen_hash_alg, - &local_err); + luks->ivgen_cipher_alg = + qcrypto_block_luks_essiv_cipher(luks_opts.cipher_alg, + luks_opts.ivgen_hash_alg, + &local_err); if (local_err) { error_propagate(errp, local_err); goto error; } } else { - ivcipheralg = luks_opts.cipher_alg; + luks->ivgen_cipher_alg = luks_opts.cipher_alg; } strcpy(luks->header.cipher_name, cipher_alg); strcpy(luks->header.cipher_mode, cipher_mode_spec); strcpy(luks->header.hash_spec, hash_alg); - luks->header.key_bytes = qcrypto_cipher_get_key_len(luks_opts.cipher_alg); + luks->header.master_key_len = + qcrypto_cipher_get_key_len(luks_opts.cipher_alg); + if (luks_opts.cipher_mode == QCRYPTO_CIPHER_MODE_XTS) { - luks->header.key_bytes *= 2; + luks->header.master_key_len *= 2; } /* Generate the salt used for hashing the master key @@ -1008,9 +1328,9 @@ qcrypto_block_luks_create(QCryptoBlock *block, } /* Generate random master key */ - masterkey = g_new0(uint8_t, luks->header.key_bytes); + masterkey = g_new0(uint8_t, luks->header.master_key_len); if (qcrypto_random_bytes(masterkey, - luks->header.key_bytes, errp) < 0) { + luks->header.master_key_len, errp) < 0) { goto error; } @@ -1018,7 +1338,7 @@ qcrypto_block_luks_create(QCryptoBlock *block, /* Setup the block device payload encryption objects */ if (qcrypto_block_init_cipher(block, luks_opts.cipher_alg, luks_opts.cipher_mode, masterkey, - luks->header.key_bytes, 1, errp) < 0) { + luks->header.master_key_len, 1, errp) < 0) { goto error; } @@ -1026,9 +1346,9 @@ qcrypto_block_luks_create(QCryptoBlock *block, block->niv = qcrypto_cipher_get_iv_len(luks_opts.cipher_alg, luks_opts.cipher_mode); block->ivgen = qcrypto_ivgen_new(luks_opts.ivgen_alg, - ivcipheralg, + luks->ivgen_cipher_alg, luks_opts.ivgen_hash_alg, - masterkey, luks->header.key_bytes, + masterkey, luks->header.master_key_len, errp); if (!block->ivgen) { @@ -1040,7 +1360,7 @@ qcrypto_block_luks_create(QCryptoBlock *block, * key, in order to have 1 second of compute time used */ iters = qcrypto_pbkdf2_count_iters(luks_opts.hash_alg, - masterkey, luks->header.key_bytes, + masterkey, luks->header.master_key_len, luks->header.master_key_salt, QCRYPTO_BLOCK_LUKS_SALT_LEN, QCRYPTO_BLOCK_LUKS_DIGEST_LEN, @@ -1080,7 +1400,7 @@ qcrypto_block_luks_create(QCryptoBlock *block, * valid master key */ if (qcrypto_pbkdf2(luks_opts.hash_alg, - masterkey, luks->header.key_bytes, + masterkey, luks->header.master_key_len, luks->header.master_key_salt, QCRYPTO_BLOCK_LUKS_SALT_LEN, luks->header.master_key_iterations, @@ -1090,143 +1410,32 @@ qcrypto_block_luks_create(QCryptoBlock *block, goto error; } + /* start with the sector that follows the header*/ + header_sectors = QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET / + QCRYPTO_BLOCK_LUKS_SECTOR_SIZE; - /* Although LUKS has multiple key slots, we're just going - * to use the first key slot */ - splitkeylen = luks->header.key_bytes * QCRYPTO_BLOCK_LUKS_STRIPES; - for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { - luks->header.key_slots[i].active = i == 0 ? - QCRYPTO_BLOCK_LUKS_KEY_SLOT_ENABLED : - QCRYPTO_BLOCK_LUKS_KEY_SLOT_DISABLED; - luks->header.key_slots[i].stripes = QCRYPTO_BLOCK_LUKS_STRIPES; - - /* This calculation doesn't match that shown in the spec, - * but instead follows the cryptsetup implementation. - */ - luks->header.key_slots[i].key_offset = - (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET / - QCRYPTO_BLOCK_LUKS_SECTOR_SIZE) + - (ROUND_UP(DIV_ROUND_UP(splitkeylen, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE), - (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET / - QCRYPTO_BLOCK_LUKS_SECTOR_SIZE)) * i); - } - - if (qcrypto_random_bytes(luks->header.key_slots[0].salt, - QCRYPTO_BLOCK_LUKS_SALT_LEN, - errp) < 0) { - goto error; - } - - /* Again we determine how many iterations are required to - * hash the user password while consuming 1 second of compute - * time */ - iters = qcrypto_pbkdf2_count_iters(luks_opts.hash_alg, - (uint8_t *)password, strlen(password), - luks->header.key_slots[0].salt, - QCRYPTO_BLOCK_LUKS_SALT_LEN, - luks->header.key_bytes, - &local_err); - if (local_err) { - error_propagate(errp, local_err); - goto error; - } - - if (iters > (ULLONG_MAX / luks_opts.iter_time)) { - error_setg_errno(errp, ERANGE, - "PBKDF iterations %llu too large to scale", - (unsigned long long)iters); - goto error; - } - - /* iter_time was in millis, but count_iters reported for secs */ - iters = iters * luks_opts.iter_time / 1000; - - if (iters > UINT32_MAX) { - error_setg_errno(errp, ERANGE, - "PBKDF iterations %llu larger than %u", - (unsigned long long)iters, UINT32_MAX); - goto error; - } - - luks->header.key_slots[0].iterations = - MAX(iters, QCRYPTO_BLOCK_LUKS_MIN_SLOT_KEY_ITERS); - - - /* Generate a key that we'll use to encrypt the master - * key, from the user's password - */ - slotkey = g_new0(uint8_t, luks->header.key_bytes); - if (qcrypto_pbkdf2(luks_opts.hash_alg, - (uint8_t *)password, strlen(password), - luks->header.key_slots[0].salt, - QCRYPTO_BLOCK_LUKS_SALT_LEN, - luks->header.key_slots[0].iterations, - slotkey, luks->header.key_bytes, - errp) < 0) { - goto error; - } - - - /* Setup the encryption objects needed to encrypt the - * master key material - */ - cipher = qcrypto_cipher_new(luks_opts.cipher_alg, - luks_opts.cipher_mode, - slotkey, luks->header.key_bytes, - errp); - if (!cipher) { - goto error; - } - - ivgen = qcrypto_ivgen_new(luks_opts.ivgen_alg, - ivcipheralg, - luks_opts.ivgen_hash_alg, - slotkey, luks->header.key_bytes, - errp); - if (!ivgen) { - goto error; - } + split_key_sectors = + qcrypto_block_luks_splitkeylen_sectors(luks, + header_sectors, + QCRYPTO_BLOCK_LUKS_STRIPES); - /* Before storing the master key, we need to vastly - * increase its size, as protection against forensic - * disk data recovery */ - splitkey = g_new0(uint8_t, splitkeylen); - - if (qcrypto_afsplit_encode(luks_opts.hash_alg, - luks->header.key_bytes, - luks->header.key_slots[0].stripes, - masterkey, - splitkey, - errp) < 0) { - goto error; - } + for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { + QCryptoBlockLUKSKeySlot *slot = &luks->header.key_slots[i]; + slot->active = QCRYPTO_BLOCK_LUKS_KEY_SLOT_DISABLED; - /* Now we encrypt the split master key with the key generated - * from the user's password, before storing it */ - if (qcrypto_block_cipher_encrypt_helper(cipher, block->niv, ivgen, - QCRYPTO_BLOCK_LUKS_SECTOR_SIZE, - 0, - splitkey, - splitkeylen, - errp) < 0) { - goto error; + slot->key_offset_sector = header_sectors + i * split_key_sectors; + slot->stripes = QCRYPTO_BLOCK_LUKS_STRIPES; } - /* The total size of the LUKS headers is the partition header + key * slot headers, rounded up to the nearest sector, combined with * the size of each master key material region, also rounded up * to the nearest sector */ - luks->header.payload_offset = - (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET / - QCRYPTO_BLOCK_LUKS_SECTOR_SIZE) + - (ROUND_UP(DIV_ROUND_UP(splitkeylen, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE), - (QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET / - QCRYPTO_BLOCK_LUKS_SECTOR_SIZE)) * - QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS); + luks->header.payload_offset_sector = header_sectors + + QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS * split_key_sectors; block->sector_size = QCRYPTO_BLOCK_LUKS_SECTOR_SIZE; - block->payload_offset = luks->header.payload_offset * + block->payload_offset = luks->header.payload_offset_sector * block->sector_size; /* Reserve header space to match payload offset */ @@ -1236,77 +1445,27 @@ qcrypto_block_luks_create(QCryptoBlock *block, goto error; } - /* Everything on disk uses Big Endian, so flip header fields - * before writing them */ - cpu_to_be16s(&luks->header.version); - cpu_to_be32s(&luks->header.payload_offset); - cpu_to_be32s(&luks->header.key_bytes); - cpu_to_be32s(&luks->header.master_key_iterations); - - for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { - cpu_to_be32s(&luks->header.key_slots[i].active); - cpu_to_be32s(&luks->header.key_slots[i].iterations); - cpu_to_be32s(&luks->header.key_slots[i].key_offset); - cpu_to_be32s(&luks->header.key_slots[i].stripes); - } - - - /* Write out the partition header and key slot headers */ - writefunc(block, 0, - (const uint8_t *)&luks->header, - sizeof(luks->header), - opaque, - &local_err); - - /* Delay checking local_err until we've byte-swapped */ - - /* Byte swap the header back to native, in case we need - * to read it again later */ - be16_to_cpus(&luks->header.version); - be32_to_cpus(&luks->header.payload_offset); - be32_to_cpus(&luks->header.key_bytes); - be32_to_cpus(&luks->header.master_key_iterations); - for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { - be32_to_cpus(&luks->header.key_slots[i].active); - be32_to_cpus(&luks->header.key_slots[i].iterations); - be32_to_cpus(&luks->header.key_slots[i].key_offset); - be32_to_cpus(&luks->header.key_slots[i].stripes); - } - - if (local_err) { - error_propagate(errp, local_err); + /* populate the slot 0 with the password encrypted master key*/ + /* This will also store the header */ + if (qcrypto_block_luks_store_key(block, + 0, + password, + masterkey, + luks_opts.iter_time, + writefunc, + opaque, + errp) < 0) { goto error; } - /* Write out the master key material, starting at the - * sector immediately following the partition header. */ - if (writefunc(block, - luks->header.key_slots[0].key_offset * - QCRYPTO_BLOCK_LUKS_SECTOR_SIZE, - splitkey, splitkeylen, - opaque, - errp) != splitkeylen) { - goto error; - } - - luks->cipher_alg = luks_opts.cipher_alg; - luks->cipher_mode = luks_opts.cipher_mode; - luks->ivgen_alg = luks_opts.ivgen_alg; - luks->ivgen_hash_alg = luks_opts.ivgen_hash_alg; - luks->hash_alg = luks_opts.hash_alg; - - memset(masterkey, 0, luks->header.key_bytes); - memset(slotkey, 0, luks->header.key_bytes); + memset(masterkey, 0, luks->header.master_key_len); return 0; error: if (masterkey) { - memset(masterkey, 0, luks->header.key_bytes); - } - if (slotkey) { - memset(slotkey, 0, luks->header.key_bytes); + memset(masterkey, 0, luks->header.master_key_len); } qcrypto_block_free_cipher(block); @@ -1346,7 +1505,7 @@ static int qcrypto_block_luks_get_info(QCryptoBlock *block, slots->value = slot = g_new0(QCryptoBlockInfoLUKSSlot, 1); slot->active = luks->header.key_slots[i].active == QCRYPTO_BLOCK_LUKS_KEY_SLOT_ENABLED; - slot->key_offset = luks->header.key_slots[i].key_offset + slot->key_offset = luks->header.key_slots[i].key_offset_sector * QCRYPTO_BLOCK_LUKS_SECTOR_SIZE; if (slot->active) { slot->has_iters = true; diff --git a/disas/cris.c b/disas/cris.c index 2f43c9b209..0b0a3fb916 100644 --- a/disas/cris.c +++ b/disas/cris.c @@ -1294,24 +1294,17 @@ static int cris_constraint /* Parse disassembler options and store state in info. FIXME: For the time being, we abuse static variables. */ -static bfd_boolean -cris_parse_disassembler_options (disassemble_info *info, +static void +cris_parse_disassembler_options (struct cris_disasm_data *disdata, + char *disassembler_options, enum cris_disass_family distype) { - struct cris_disasm_data *disdata; - - info->private_data = calloc (1, sizeof (struct cris_disasm_data)); - disdata = (struct cris_disasm_data *) info->private_data; - if (disdata == NULL) - return false; - /* Default true. */ disdata->trace_case - = (info->disassembler_options == NULL - || (strcmp (info->disassembler_options, "nocase") != 0)); + = (disassembler_options == NULL + || (strcmp (disassembler_options, "nocase") != 0)); disdata->distype = distype; - return true; } static const struct cris_spec_reg * @@ -2736,9 +2729,10 @@ static int print_insn_cris_with_register_prefix (bfd_vma vma, disassemble_info *info) { - if (info->private_data == NULL - && !cris_parse_disassembler_options (info, cris_dis_v0_v10)) - return -1; + struct cris_disasm_data disdata; + info->private_data = &disdata; + cris_parse_disassembler_options (&disdata, info->disassembler_options, + cris_dis_v0_v10); return print_insn_cris_generic (vma, info, true); } /* Disassemble, prefixing register names with `$'. CRIS v32. */ @@ -2747,9 +2741,10 @@ static int print_insn_crisv32_with_register_prefix (bfd_vma vma, disassemble_info *info) { - if (info->private_data == NULL - && !cris_parse_disassembler_options (info, cris_dis_v32)) - return -1; + struct cris_disasm_data disdata; + info->private_data = &disdata; + cris_parse_disassembler_options (&disdata, info->disassembler_options, + cris_dis_v32); return print_insn_cris_generic (vma, info, true); } @@ -2761,9 +2756,10 @@ static int print_insn_crisv10_v32_with_register_prefix (bfd_vma vma, disassemble_info *info) { - if (info->private_data == NULL - && !cris_parse_disassembler_options (info, cris_dis_common_v10_v32)) - return -1; + struct cris_disasm_data disdata; + info->private_data = &disdata; + cris_parse_disassembler_options (&disdata, info->disassembler_options, + cris_dis_common_v10_v32); return print_insn_cris_generic (vma, info, true); } @@ -2773,9 +2769,10 @@ static int print_insn_cris_without_register_prefix (bfd_vma vma, disassemble_info *info) { - if (info->private_data == NULL - && !cris_parse_disassembler_options (info, cris_dis_v0_v10)) - return -1; + struct cris_disasm_data disdata; + info->private_data = &disdata; + cris_parse_disassembler_options (&disdata, info->disassembler_options, + cris_dis_v0_v10); return print_insn_cris_generic (vma, info, false); } @@ -2785,9 +2782,10 @@ static int print_insn_crisv32_without_register_prefix (bfd_vma vma, disassemble_info *info) { - if (info->private_data == NULL - && !cris_parse_disassembler_options (info, cris_dis_v32)) - return -1; + struct cris_disasm_data disdata; + info->private_data = &disdata; + cris_parse_disassembler_options (&disdata, info->disassembler_options, + cris_dis_v32); return print_insn_cris_generic (vma, info, false); } @@ -2798,9 +2796,10 @@ static int print_insn_crisv10_v32_without_register_prefix (bfd_vma vma, disassemble_info *info) { - if (info->private_data == NULL - && !cris_parse_disassembler_options (info, cris_dis_common_v10_v32)) - return -1; + struct cris_disasm_data disdata; + info->private_data = &disdata; + cris_parse_disassembler_options (&disdata, info->disassembler_options, + cris_dis_common_v10_v32); return print_insn_cris_generic (vma, info, false); } #endif diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt index e8ec8ac1de..64d9e4c6a9 100644 --- a/docs/devel/qapi-code-gen.txt +++ b/docs/devel/qapi-code-gen.txt @@ -4,262 +4,99 @@ Copyright IBM Corp. 2011 Copyright (C) 2012-2016 Red Hat, Inc. This work is licensed under the terms of the GNU GPL, version 2 or -later. See the COPYING file in the top-level directory. +later. See the COPYING file in the top-level directory. == Introduction == QAPI is a native C API within QEMU which provides management-level -functionality to internal and external users. For external +functionality to internal and external users. For external users/processes, this interface is made available by a JSON-based wire format for the QEMU Monitor Protocol (QMP) for controlling qemu, as well as the QEMU Guest Agent (QGA) for communicating with the guest. The remainder of this document uses "Client JSON Protocol" when referring to the wire contents of a QMP or QGA connection. -To map Client JSON Protocol interfaces to the native C QAPI -implementations, a JSON-based schema is used to define types and -function signatures, and a set of scripts is used to generate types, -signatures, and marshaling/dispatch code. This document will describe -how the schemas, scripts, and resulting code are used. +To map between Client JSON Protocol interfaces and the native C API, +we generate C code from a QAPI schema. This document describes the +QAPI schema language, and how it gets mapped to the Client JSON +Protocol and to C. It additionally provides guidance on maintaining +Client JSON Protocol compatibility. -== QMP/Guest agent schema == +== The QAPI schema language == -A QAPI schema file is designed to be loosely based on JSON -(http://www.ietf.org/rfc/rfc8259.txt) with changes for quoting style -and the use of comments; a QAPI schema file is then parsed by a python -code generation program. A valid QAPI schema consists of a series of -top-level expressions, with no commas between them. Where -dictionaries (JSON objects) are used, they are parsed as python -OrderedDicts so that ordering is preserved (for predictable layout of -generated C structs and parameter lists). Ordering doesn't matter -between top-level expressions or the keys within an expression, but -does matter within dictionary values for 'data' and 'returns' members -of a single expression. QAPI schema input is written using 'single -quotes' instead of JSON's "double quotes" (in contrast, Client JSON -Protocol uses no comments, and while input accepts 'single quotes' as -an extension, output is strict JSON using only "double quotes"). As -in JSON, trailing commas are not permitted in arrays or dictionaries. -Input must be ASCII (although QMP supports full Unicode strings, the -QAPI parser does not). At present, there is no place where a QAPI -schema requires the use of JSON numbers or null. +The QAPI schema defines the Client JSON Protocol's commands and +events, as well as types used by them. Forward references are +allowed. +It is permissible for the schema to contain additional types not used +by any commands or events, for the side effect of generated C code +used internally. -=== Comments === +There are several kinds of types: simple types (a number of built-in +types, such as 'int' and 'str'; as well as enumerations), arrays, +complex types (structs and two flavors of unions), and alternate types +(a choice between other types). -Comments are allowed; anything between an unquoted # and the following -newline is ignored. -A multi-line comment that starts and ends with a '##' line is a -documentation comment. These are parsed by the documentation -generator, which recognizes certain markup detailed below. - - -==== Documentation markup ==== - -Comment text starting with '=' is a section title: - - # = Section title - -Double the '=' for a subsection title: - - # == Subsection title +=== Schema syntax === -'|' denotes examples: - - # | Text of the example, may span - # | multiple lines - -'*' starts an itemized list: +Syntax is loosely based on JSON (http://www.ietf.org/rfc/rfc8259.txt). +Differences: - # * First item, may span - # multiple lines - # * Second item +* Comments: start with a hash character (#) that is not part of a + string, and extend to the end of the line. -You can also use '-' instead of '*'. +* Strings are enclosed in 'single quotes', not "double quotes". -A decimal number followed by '.' starts a numbered list: +* Strings are restricted to printable ASCII, and escape sequences to + just '\\'. - # 1. First item, may span - # multiple lines - # 2. Second item - -The actual number doesn't matter. You could even use '*' instead of -'2.' for the second item. - -Lists can't be nested. Blank lines are currently not supported within -lists. - -Additional whitespace between the initial '#' and the comment text is -permitted. - -*foo* and _foo_ are for strong and emphasis styles respectively (they -do not work over multiple lines). @foo is used to reference a name in -the schema. - -Example: - -## -# = Section -# == Subsection -# -# Some text foo with *strong* and _emphasis_ -# 1. with a list -# 2. like that -# -# And some code: -# | $ echo foo -# | -> do this -# | <- get that -# -## - - -==== Expression documentation ==== - -Each expression that isn't an include directive may be preceded by a -documentation block. Such blocks are called expression documentation -blocks. - -When documentation is required (see pragma 'doc-required'), expression -documentation blocks are mandatory. - -The documentation block consists of a first line naming the -expression, an optional overview, a description of each argument (for -commands and events) or member (for structs, unions and alternates), -and optional tagged sections. - -FIXME: the parser accepts these things in almost any order. - -Extensions added after the expression was first released carry a -'(since x.y.z)' comment. - -A tagged section starts with one of the following words: -"Note:"/"Notes:", "Since:", "Example"/"Examples", "Returns:", "TODO:". -The section ends with the start of a new section. - -A 'Since: x.y.z' tagged section lists the release that introduced the -expression. - -For example: - -## -# @BlockStats: -# -# Statistics of a virtual block device or a block backing device. -# -# @device: If the stats are for a virtual block device, the name -# corresponding to the virtual block device. -# -# @node-name: The node name of the device. (since 2.3) -# -# ... more members ... -# -# Since: 0.14.0 -## -{ 'struct': 'BlockStats', - 'data': {'*device': 'str', '*node-name': 'str', - ... more members ... } } - -## -# @query-blockstats: -# -# Query the @BlockStats for all virtual block devices. -# -# @query-nodes: If true, the command will query all the -# block nodes ... explain, explain ... (since 2.3) -# -# Returns: A list of @BlockStats for each virtual block devices. -# -# Since: 0.14.0 -# -# Example: -# -# -> { "execute": "query-blockstats" } -# <- { -# ... lots of output ... -# } -# -## -{ 'command': 'query-blockstats', - 'data': { '*query-nodes': 'bool' }, - 'returns': ['BlockStats'] } +* Numbers and null are not supported. -==== Free-form documentation ==== - -A documentation block that isn't an expression documentation block is -a free-form documentation block. These may be used to provide -additional text and structuring content. - - -=== Schema overview === - -The schema sets up a series of types, as well as commands and events -that will use those types. Forward references are allowed: the parser -scans in two passes, where the first pass learns all type names, and -the second validates the schema and generates the code. This allows -the definition of complex structs that can have mutually recursive -types, and allows for indefinite nesting of Client JSON Protocol that -satisfies the schema. A type name should not be defined more than -once. It is permissible for the schema to contain additional types -not used by any commands or events in the Client JSON Protocol, for -the side effect of generated C code used internally. - -There are eight top-level expressions recognized by the parser: -'include', 'pragma', 'command', 'struct', 'enum', 'union', -'alternate', and 'event'. There are several groups of types: simple -types (a number of built-in types, such as 'int' and 'str'; as well as -enumerations), complex types (structs and two flavors of unions), and -alternate types (a choice between other types). The 'command' and -'event' expressions can refer to existing types by name, or list an -anonymous type as a dictionary. Listing a type name inside an array -refers to a single-dimension array of that type; multi-dimension -arrays are not directly supported (although an array of a complex -struct that contains an array member is possible). +A second layer of syntax defines the sequences of JSON texts that are +a correctly structured QAPI schema. We provide a grammar for this +syntax in an EBNF-like notation: -All names must begin with a letter, and contain only ASCII letters, -digits, hyphen, and underscore. There are two exceptions: enum values -may start with a digit, and names that are downstream extensions (see -section Downstream extensions) start with underscore. +* Production rules look like non-terminal = expression +* Concatenation: expression A B matches expression A, then B +* Alternation: expression A | B matches expression A or B +* Repetition: expression A... matches zero or more occurrences of + expression A +* Repetition: expression A, ... matches zero or more occurrences of + expression A separated by , +* Grouping: expression ( A ) matches expression A +* JSON's structural characters are terminals: { } [ ] : , +* JSON's literal names are terminals: false true +* String literals enclosed in 'single quotes' are terminal, and match + this JSON string, with a leading '*' stripped off +* When JSON object member's name starts with '*', the member is + optional. +* The symbol STRING is a terminal, and matches any JSON string +* The symbol BOOL is a terminal, and matches JSON false or true +* ALL-CAPS words other than STRING are non-terminals -Names beginning with 'q_' are reserved for the generator, which uses -them for munging QMP names that resemble C keywords or other -problematic strings. For example, a member named "default" in qapi -becomes "q_default" in the generated C code. +The order of members within JSON objects does not matter unless +explicitly noted. -Types, commands, and events share a common namespace. Therefore, -generally speaking, type definitions should always use CamelCase for -user-defined type names, while built-in types are lowercase. +A QAPI schema consists of a series of top-level expressions: -Type names ending with 'Kind' or 'List' are reserved for the -generator, which uses them for implicit union enums and array types, -respectively. + SCHEMA = TOP-LEVEL-EXPR... -Command names, and member names within a type, should be all lower -case with words separated by a hyphen. However, some existing older -commands and complex types use underscore; when extending such -expressions, consistency is preferred over blindly avoiding -underscore. +The top-level expressions are all JSON objects. Code and +documentation is generated in schema definition order. Code order +should not matter. -Event names should be ALL_CAPS with words separated by underscore. +A top-level expressions is either a directive or a definition: -Member names starting with 'has-' or 'has_' are reserved for the -generator, which uses them for tracking optional members. + TOP-LEVEL-EXPR = DIRECTIVE | DEFINITION -Any name (command, event, type, member, or enum value) beginning with -"x-" is marked experimental, and may be withdrawn or changed -incompatibly in a future release. +There are two kinds of directives and six kinds of definitions: -Pragma 'name-case-whitelist' lets you violate the rules on use of -upper and lower case. Use for new code is strongly discouraged. + DIRECTIVE = INCLUDE | PRAGMA + DEFINITION = ENUM | STRUCT | UNION | ALTERNATE | COMMAND | EVENT -In the rest of this document, usage lines are given for each -expression type, with literal strings written in lower case and -placeholders written in capitals. If a literal string includes a -prefix of '*', that key/value pair can be omitted from the expression. -For example, a usage statement that includes '*base':STRUCT-NAME -means that an expression has an optional key 'base', which if present -must have a value that forms a struct name. +These are discussed in detail below. === Built-in Types === @@ -289,16 +126,16 @@ The following types are predefined, and map to C as follows: === Include directives === -Usage: { 'include': STRING } +Syntax: + INCLUDE = { 'include': STRING } The QAPI schema definitions can be modularized using the 'include' directive: { 'include': 'path/to/file.json' } -The directive is evaluated recursively, and include paths are relative to the -file using the directive. Multiple includes of the same file are -idempotent. No other keys should appear in the expression, and the include -value should be a string. +The directive is evaluated recursively, and include paths are relative +to the file using the directive. Multiple includes of the same file +are idempotent. As a matter of style, it is a good idea to have all files be self-contained, but at the moment, nothing prevents an included file @@ -309,10 +146,12 @@ prevent incomplete include files. === Pragma directives === -Usage: { 'pragma': DICT } +Syntax: + PRAGMA = { 'pragma': { '*doc-required': BOOL, + '*returns-whitelist': [ STRING, ... ], + '*name-case-whitelist': [ STRING, ... ] } } The pragma directive lets you control optional generator behavior. -The dictionary's entries are pragma names and values. Pragma's scope is currently the complete schema. Setting the same pragma to different values in parts of the schema doesn't work. @@ -327,56 +166,97 @@ Pragma 'name-case-whitelist' takes a list of names that may violate rules on use of upper- vs. lower-case letters. Default is none. +=== Enumeration types === + +Syntax: + ENUM = { 'enum': STRING, + 'data': [ ENUM-VALUE, ... ], + '*prefix': STRING, + '*if': COND } + ENUM-VALUE = STRING + | { 'name': STRING, '*if': COND } + +Member 'enum' names the enum type. + +Each member of the 'data' array defines a value of the enumeration +type. The form STRING is shorthand for { 'name': STRING }. The +'name' values must be be distinct. + +Example: + + { 'enum': 'MyEnum', 'data': [ 'value1', 'value2', 'value3' ] } + +Nothing prevents an empty enumeration, although it is probably not +useful. + +On the wire, an enumeration type's value is represented by its +(string) name. In C, it's represented by an enumeration constant. +These are of the form PREFIX_NAME, where PREFIX is derived from the +enumeration type's name, and NAME from the value's name. For the +example above, the generator maps 'MyEnum' to MY_ENUM and 'value1' to +VALUE1, resulting in the enumeration constant MY_ENUM_VALUE1. The +optional 'prefix' member overrides PREFIX. + +The generated C enumeration constants have values 0, 1, ..., N-1 (in +QAPI schema order), where N is the number of values. There is an +additional enumeration constant PREFIX__MAX with value N. + +Do not use string or an integer type when an enumeration type can do +the job satisfactorily. + +The optional 'if' member specifies a conditional. See "Configuring +the schema" below for more on this. + + +=== Type references and array types === + +Syntax: + TYPE-REF = STRING | ARRAY-TYPE + ARRAY-TYPE = [ STRING ] + +A string denotes the type named by the string. + +A one-element array containing a string denotes an array of the type +named by the string. Example: ['int'] denotes an array of 'int'. + + === Struct types === -Usage: { 'struct': STRING, 'data': DICT, '*base': STRUCT-NAME } +Syntax: + STRUCT = { 'struct': STRING, + 'data': MEMBERS, + '*base': STRING, + '*if': COND, + '*features': FEATURES } + MEMBERS = { MEMBER, ... } + MEMBER = STRING : TYPE-REF + | STRING : { 'type': TYPE-REF, '*if': COND } + +Member 'struct' names the struct type. -A struct is a dictionary containing a single 'data' key whose value is -a dictionary; the dictionary may be empty. This corresponds to a -struct in C or an Object in JSON. Each value of the 'data' dictionary -must be the name of a type, or a one-element array containing a type -name. An example of a struct is: +Each MEMBER of the 'data' object defines a member of the struct type. + +The MEMBER's STRING name consists of an optional '*' prefix and the +struct member name. If '*' is present, the member is optional. + +The MEMBER's value defines its properties, in particular its type. +The form TYPE-REF is shorthand for { 'type': TYPE-REF }. + +Example: { 'struct': 'MyType', - 'data': { 'member1': 'str', 'member2': 'int', '*member3': 'str' } } - -The use of '*' as a prefix to the name means the member is optional in -the corresponding JSON protocol usage. - -The default initialization value of an optional argument should not be changed -between versions of QEMU unless the new default maintains backward -compatibility to the user-visible behavior of the old default. - -With proper documentation, this policy still allows some flexibility; for -example, documenting that a default of 0 picks an optimal buffer size allows -one release to declare the optimal size at 512 while another release declares -the optimal size at 4096 - the user-visible behavior is not the bytes used by -the buffer, but the fact that the buffer was optimal size. - -On input structures (only mentioned in the 'data' side of a command), changing -from mandatory to optional is safe (older clients will supply the option, and -newer clients can benefit from the default); changing from optional to -mandatory is backwards incompatible (older clients may be omitting the option, -and must continue to work). - -On output structures (only mentioned in the 'returns' side of a command), -changing from mandatory to optional is in general unsafe (older clients may be -expecting the member, and could crash if it is missing), although it -can be done if the only way that the optional argument will be omitted -is when it is triggered by the presence of a new input flag to the -command that older clients don't know to send. Changing from optional -to mandatory is safe. - -A structure that is used in both input and output of various commands -must consider the backwards compatibility constraints of both directions -of use. - -A struct definition can specify another struct as its base. -In this case, the members of the base type are included as top-level members -of the new struct's dictionary in the Client JSON Protocol wire -format. An example definition is: - - { 'struct': 'BlockdevOptionsGenericFormat', 'data': { 'file': 'str' } } + 'data': { 'member1': 'str', 'member2': ['int'], '*member3': 'str' } } + +A struct type corresponds to a struct in C, and an object in JSON. +The C struct's members are generated in QAPI schema order. + +The optional 'base' member names a struct type whose members are to be +included in this type. They go first in the C struct. + +Example: + + { 'struct': 'BlockdevOptionsGenericFormat', + 'data': { 'file': 'str' } } { 'struct': 'BlockdevOptionsGenericCOWFormat', 'base': 'BlockdevOptionsGenericFormat', 'data': { '*backing': 'str' } } @@ -387,56 +267,40 @@ both members like this: { "file": "/some/place/my-image", "backing": "/some/place/my-backing-file" } +The optional 'if' member specifies a conditional. See "Configuring +the schema" below for more on this. -=== Enumeration types === +The optional 'features' member specifies features. See "Features" +below for more on this. -Usage: { 'enum': STRING, 'data': ARRAY-OF-STRING } - { 'enum': STRING, '*prefix': STRING, 'data': ARRAY-OF-STRING } -An enumeration type is a dictionary containing a single 'data' key -whose value is a list of strings. An example enumeration is: +=== Union types === - { 'enum': 'MyEnum', 'data': [ 'value1', 'value2', 'value3' ] } +Syntax: + UNION = { 'union': STRING, + 'data': BRANCHES, + '*if': COND } + | { 'union': STRING, + 'data': BRANCHES, + 'base': ( MEMBERS | STRING ), + 'discriminator': STRING, + '*if': COND } + BRANCHES = { BRANCH, ... } + BRANCH = STRING : TYPE-REF + | STRING : { 'type': TYPE-REF, '*if': COND } -Nothing prevents an empty enumeration, although it is probably not -useful. The list of strings should be lower case; if an enum name -represents multiple words, use '-' between words. The string 'max' is -not allowed as an enum value, and values should not be repeated. - -The enum constants will be named by using a heuristic to turn the -type name into a set of underscore separated words. For the example -above, 'MyEnum' will turn into 'MY_ENUM' giving a constant name -of 'MY_ENUM_VALUE1' for the first value. If the default heuristic -does not result in a desirable name, the optional 'prefix' member -can be used when defining the enum. - -The enumeration values are passed as strings over the Client JSON -Protocol, but are encoded as C enum integral values in generated code. -While the C code starts numbering at 0, it is better to use explicit -comparisons to enum values than implicit comparisons to 0; the C code -will also include a generated enum member ending in _MAX for tracking -the size of the enum, useful when using common functions for -converting between strings and enum values. Since the wire format -always passes by name, it is acceptable to reorder or add new -enumeration members in any location without breaking clients of Client -JSON Protocol; however, removing enum values would break -compatibility. For any struct that has a member that will only contain -a finite set of string values, using an enum type for that member is -better than open-coding the member to be type 'str'. +Member 'union' names the union type. +There are two flavors of union types: simple (no discriminator or +base), and flat (both discriminator and base). -=== Union types === +Each BRANCH of the 'data' object defines a branch of the union. A +union must have at least one branch. -Usage: { 'union': STRING, 'data': DICT } -or: { 'union': STRING, 'data': DICT, 'base': STRUCT-NAME-OR-DICT, - 'discriminator': ENUM-MEMBER-OF-BASE } +The BRANCH's STRING name is the branch name. -Union types are used to let the user choose between several different -variants for an object. There are two flavors: simple (no -discriminator or base), and flat (both discriminator and base). A union -type is defined using a data dictionary as explained in the following -paragraphs. The data dictionary for either type of union must not -be empty. +The BRANCH's value defines the branch's properties, in particular its +type. The form TYPE-REF is shorthand for { 'type': TYPE-REF }. A simple union type defines a mapping from automatic discriminator values to data types like in this example: @@ -449,8 +313,8 @@ values to data types like in this example: 'data': { 'file': 'BlockdevOptionsFile', 'qcow2': 'BlockdevOptionsQcow2' } } -In the Client JSON Protocol, a simple union is represented by a -dictionary that contains the 'type' member as a discriminator, and a +In the Client JSON Protocol, a simple union is represented by an +object that contains the 'type' member as a discriminator, and a 'data' member that is of the specified data type corresponding to the discriminator value, as in these examples: @@ -458,22 +322,27 @@ discriminator value, as in these examples: { "type": "qcow2", "data": { "backing": "/some/place/my-image", "lazy-refcounts": true } } -The generated C code uses a struct containing a union. Additionally, +The generated C code uses a struct containing a union. Additionally, an implicit C enum 'NameKind' is created, corresponding to the union -'Name', for accessing the various branches of the union. No branch of -the union can be named 'max', as this would collide with the implicit -enum. The value for each branch can be of any type. - -A flat union definition avoids nesting on the wire, and specifies a -set of common members that occur in all variants of the union. The -'base' key must specify either a type name (the type must be a -struct, not a union), or a dictionary representing an anonymous type. -All branches of the union must be complex types, and the top-level -members of the union dictionary on the wire will be combination of -members from both the base type and the appropriate branch type (when -merging two dictionaries, there must be no keys in common). The -'discriminator' member must be the name of a non-optional enum-typed -member of the base struct. +'Name', for accessing the various branches of the union. The value +for each branch can be of any type. + +Flat unions permit arbitrary common members that occur in all variants +of the union, not just a discriminator. Their discriminators need not +be named 'type'. They also avoid nesting on the wire. + +The 'base' member defines the common members. If it is a MEMBERS +object, it defines common members just like a struct type's 'data' +member defines struct type members. If it is a STRING, it names a +struct type whose members are the common members. + +All flat union branches must be of struct type. + +In the Client JSON Protocol, a flat union is represented by an object +with the common members (from the base type) and the selected branch's +members. The two sets of member names must be disjoint. Member +'discriminator' must name a non-optional enum-typed member of the base +struct. The following example enhances the above simple union example by adding an optional common member 'read-only', renaming the @@ -497,12 +366,13 @@ Resulting in these JSON objects: Notice that in a flat union, the discriminator name is controlled by the user, but because it must map to a base member with enum type, the code generator ensures that branches match the existing values of the -enum. The order of the keys need not match the declaration of the enum. -The keys need not cover all possible enum values. Omitted enum values -are still valid branches that add no additional members to the data type. -In the resulting generated C data types, a flat union is -represented as a struct with the base members included directly, and -then a union of structures for each branch of the struct. +enum. The order of branches need not match the order of the enum +values. The branches need not cover all possible enum values. +Omitted enum values are still valid branches that add no additional +members to the data type. In the resulting generated C data types, a +flat union is represented as a struct with the base members in QAPI +schema order, and then a union of structures for each branch of the +struct. A simple union can always be re-written as a flat union where the base class has a single member named 'type', and where each branch of the @@ -518,32 +388,47 @@ is identical on the wire to: { 'union': 'Flat': 'base': { 'type': 'Enum' }, 'discriminator': 'type', 'data': { 'one': 'Branch1', 'two': 'Branch2' } } +The optional 'if' member specifies a conditional. See "Configuring +the schema" below for more on this. + === Alternate types === -Usage: { 'alternate': STRING, 'data': DICT } +Syntax: + ALTERNATE = { 'alternate': STRING, + 'data': ALTERNATIVES, + '*if': COND } + ALTERNATIVES = { ALTERNATIVE, ... } + ALTERNATIVE = STRING : TYPE-REF + | STRING : { 'type': STRING, '*if': COND } + +Member 'alternate' names the alternate type. -An alternate type is one that allows a choice between two or more JSON -data types (string, integer, number, or object, but currently not -array) on the wire. The definition is similar to a simple union type, -where each branch of the union names a QAPI type. For example: +Each ALTERNATIVE of the 'data' object defines a branch of the +alternate. An alternate must have at least one branch. + +The ALTERNATIVE's STRING name is the branch name. + +The ALTERNATIVE's value defines the branch's properties, in particular +its type. The form STRING is shorthand for { 'type': STRING }. + +Example: { 'alternate': 'BlockdevRef', 'data': { 'definition': 'BlockdevOptions', 'reference': 'str' } } -Unlike a union, the discriminator string is never passed on the wire -for the Client JSON Protocol. Instead, the value's JSON type serves -as an implicit discriminator, which in turn means that an alternate -can only express a choice between types represented differently in -JSON. If a branch is typed as the 'bool' built-in, the alternate -accepts true and false; if it is typed as any of the various numeric +An alternate type is like a union type, except there is no +discriminator on the wire. Instead, the branch to use is inferred +from the value. An alternate can only express a choice between types +represented differently on the wire. + +If a branch is typed as the 'bool' built-in, the alternate accepts +true and false; if it is typed as any of the various numeric built-ins, it accepts a JSON number; if it is typed as a 'str' built-in or named enum type, it accepts a JSON string; if it is typed as the 'null' built-in, it accepts JSON null; and if it is typed as a -complex type (struct or union), it accepts a JSON object. Two -different complex types, for instance, aren't permitted, because both -are represented as a JSON object. +complex type (struct or union), it accepts a JSON object. The example alternate declaration above allows using both of the following example objects: @@ -553,43 +438,52 @@ following example objects: "read-only": false, "filename": "/tmp/mydisk.qcow2" } } +The optional 'if' member specifies a conditional. See "Configuring +the schema" below for more on this. + === Commands === ---- General Command Layout --- - -Usage: { 'command': STRING, '*data': COMPLEX-TYPE-NAME-OR-DICT, - '*returns': TYPE-NAME, '*boxed': true, - '*gen': false, '*success-response': false, - '*allow-oob': true, '*allow-preconfig': true } - -Commands are defined by using a dictionary containing several members, -where three members are most common. The 'command' member is a -mandatory string, and determines the "execute" value passed in a -Client JSON Protocol command exchange. - -The 'data' argument maps to the "arguments" dictionary passed in as -part of a Client JSON Protocol command. The 'data' member is optional -and defaults to {} (an empty dictionary). If present, it must be the -string name of a complex type, or a dictionary that declares an -anonymous type with the same semantics as a 'struct' expression. - -The 'returns' member describes what will appear in the "return" member -of a Client JSON Protocol reply on successful completion of a command. -The member is optional from the command declaration; if absent, the -"return" member will be an empty dictionary. If 'returns' is present, -it must be the string name of a complex or built-in type, a -one-element array containing the name of a complex or built-in type. -To return anything else, you have to list the command in pragma -'returns-whitelist'. If you do this, the command cannot be extended -to return additional information in the future. Use of +Syntax: + COMMAND = { 'command': STRING, + ( + '*data': ( MEMBERS | STRING ), + | + 'data': STRING, + 'boxed': true, + ) + '*returns': TYPE-REF, + '*success-response': false, + '*gen': false, + '*allow-oob': true, + '*allow-preconfig': true, + '*if': COND } + +Member 'command' names the command. + +Member 'data' defines the arguments. It defaults to an empty MEMBERS +object. + +If 'data' is a MEMBERS object, then MEMBERS defines arguments just +like a struct type's 'data' defines struct type members. + +If 'data' is a STRING, then STRING names a complex type whose members +are the arguments. A union type requires 'boxed': true. + +Member 'returns' defines the command's return type. It defaults to an +empty struct type. It must normally be a complex type or an array of +a complex type. To return anything else, the command must be listed +in pragma 'returns-whitelist'. If you do this, extending the command +to return additional information will be harder. Use of 'returns-whitelist' for new commands is strongly discouraged. -All commands in Client JSON Protocol use a dictionary to report -failure, with no way to specify that in QAPI. Where the error return -is different than the usual GenericError class in order to help the -client react differently to certain error conditions, it is worth -documenting this in the comments before the command declaration. +A command's error responses are not specified in the QAPI schema. +Error conditions should be documented in comments. + +In the Client JSON Protocol, the value of the "execute" or "exec-oob" +member is the command name. The value of the "arguments" member then +has to conform to the arguments, and the value of the success +response's "return" member will conform to the return type. Some example commands: @@ -607,23 +501,24 @@ which would validate this Client JSON Protocol transaction: => { "execute": "my-second-command" } <= { "return": [ { "value": "one" }, { } ] } -The generator emits a prototype for the user's function implementing -the command. Normally, 'data' is a dictionary for an anonymous type, -or names a struct type (possibly empty, but not a union), and its -members are passed as separate arguments to this function. If the -command definition includes a key 'boxed' with the boolean value true, -then 'data' is instead the name of any non-empty complex type -(struct, union, or alternate), and a pointer to that QAPI type is -passed as a single argument. +The generator emits a prototype for the C function implementing the +command. The function itself needs to be written by hand. See +section "Code generated for commands" for examples. + +The function returns the return type. When member 'boxed' is absent, +it takes the command arguments as arguments one by one, in QAPI schema +order. Else it takes them wrapped in the C struct generated for the +complex argument type. It takes an additional Error ** argument in +either case. The generator also emits a marshalling function that extracts arguments for the user's function out of an input QDict, calls the user's function, and if it succeeded, builds an output QObject from -its return value. +its return value. This is for use by the QMP monitor core. In rare cases, QAPI cannot express a type-safe representation of a corresponding Client JSON Protocol command. You then have to suppress -generation of a marshalling function by including a key 'gen' with +generation of a marshalling function by including a member 'gen' with boolean value false, and instead write your own function. For example: @@ -637,13 +532,12 @@ use type-safe unions. Normally, the QAPI schema is used to describe synchronous exchanges, where a response is expected. But in some cases, the action of a command is expected to change state in a way that a successful -response is not possible (although the command will still return a -normal dictionary error on failure). When a successful reply is not -possible, the command expression includes the optional key -'success-response' with boolean value false. So far, only QGA makes -use of this member. +response is not possible (although the command will still return an +error object on failure). When a successful reply is not possible, +the command definition includes the optional member 'success-response' +with boolean value false. So far, only QGA makes use of this member. -Key 'allow-oob' declares whether the command supports out-of-band +Member 'allow-oob' declares whether the command supports out-of-band (OOB) execution. It defaults to false. For example: { 'command': 'migrate_recover', @@ -676,8 +570,8 @@ other "slow" lock. When in doubt, do not implement OOB execution support. -Key 'allow-preconfig' declares whether the command is available before -the machine is built. It defaults to false. For example: +Member 'allow-preconfig' declares whether the command is available +before the machine is built. It defaults to false. For example: { 'command': 'qmp_capabilities', 'data': { '*enable': [ 'QMPCapability' ] }, @@ -686,18 +580,33 @@ the machine is built. It defaults to false. For example: QMP is available before the machine is built only when QEMU was started with --preconfig. +The optional 'if' member specifies a conditional. See "Configuring +the schema" below for more on this. + + === Events === -Usage: { 'event': STRING, '*data': COMPLEX-TYPE-NAME-OR-DICT, - '*boxed': true } +Syntax: + EVENT = { 'event': STRING, + ( + '*data': ( MEMBERS | STRING ), + | + 'data': STRING, + 'boxed': true, + ) + '*if': COND } + +Member 'event' names the event. This is the event name used in the +Client JSON Protocol. -Events are defined with the keyword 'event'. It is not allowed to -name an event 'MAX', since the generator also produces a C enumeration -of all event names with a generated _MAX value at the end. When -'data' is also specified, additional info will be included in the -event, with similar semantics to a 'struct' expression. Finally there -will be C API generated in qapi-events.h; when called by QEMU code, a -message with timestamp will be emitted on the wire. +Member 'data' defines the event-specific data. It defaults to an +empty MEMBERS object. + +If 'data' is a MEMBERS object, then MEMBERS defines event-specific +data just like a struct type's 'data' defines struct type members. + +If 'data' is a STRING, then STRING names a complex type whose members +are the event-specific data. A union type requires 'boxed': true. An example event is: @@ -710,41 +619,82 @@ Resulting in this JSON object: "data": { "b": "test string" }, "timestamp": { "seconds": 1267020223, "microseconds": 435656 } } -The generator emits a function to send the event. Normally, 'data' is -a dictionary for an anonymous type, or names a struct type (possibly -empty, but not a union), and its members are passed as separate -arguments to this function. If the event definition includes a key -'boxed' with the boolean value true, then 'data' is instead the name of -any non-empty complex type (struct, union, or alternate), and a -pointer to that QAPI type is passed as a single argument. +The generator emits a function to send the event. When member 'boxed' +is absent, it takes event-specific data one by one, in QAPI schema +order. Else it takes them wrapped in the C struct generated for the +complex type. See section "Code generated for events" for examples. + +The optional 'if' member specifies a conditional. See "Configuring +the schema" below for more on this. === Features === +Syntax: + FEATURES = [ FEATURE, ... ] + FEATURE = STRING + | { 'name': STRING, '*if': COND } + Sometimes, the behaviour of QEMU changes compatibly, but without a -change in the QMP syntax (usually by allowing values or operations that -previously resulted in an error). QMP clients may still need to know -whether the extension is available. +change in the QMP syntax (usually by allowing values or operations +that previously resulted in an error). QMP clients may still need to +know whether the extension is available. For this purpose, a list of features can be specified for a struct type. This is exposed to the client as a list of string, where each string signals that this build of QEMU shows a certain behaviour. -In the schema, features can be specified as simple strings, for example: +Each member of the 'features' array defines a feature. It can either +be { 'name': STRING, '*if': COND }, or STRING, which is shorthand for +{ 'name': STRING }. + +The optional 'if' member specifies a conditional. See "Configuring +the schema" below for more on this. + +Example: { 'struct': 'TestType', 'data': { 'number': 'int' }, 'features': [ 'allow-negative-numbers' ] } -Another option is to specify features as dictionaries, where the key -'name' specifies the feature string to be exposed to clients: -{ 'struct': 'TestType', - 'data': { 'number': 'int' }, - 'features': [ { 'name': 'allow-negative-numbers' } ] } +=== Naming rules and reserved names === -This expanded form is necessary if you want to make the feature -conditional (see below in "Configuring the schema"). +All names must begin with a letter, and contain only ASCII letters, +digits, hyphen, and underscore. There are two exceptions: enum values +may start with a digit, and names that are downstream extensions (see +section Downstream extensions) start with underscore. + +Names beginning with 'q_' are reserved for the generator, which uses +them for munging QMP names that resemble C keywords or other +problematic strings. For example, a member named "default" in qapi +becomes "q_default" in the generated C code. + +Types, commands, and events share a common namespace. Therefore, +generally speaking, type definitions should always use CamelCase for +user-defined type names, while built-in types are lowercase. + +Type names ending with 'Kind' or 'List' are reserved for the +generator, which uses them for implicit union enums and array types, +respectively. + +Command names, and member names within a type, should be all lower +case with words separated by a hyphen. However, some existing older +commands and complex types use underscore; when extending them, +consistency is preferred over blindly avoiding underscore. + +Event names should be ALL_CAPS with words separated by underscore. + +Member name 'u' and names starting with 'has-' or 'has_' are reserved +for the generator, which uses them for unions and for tracking +optional members. + +Any name (command, event, type, member, or enum value) beginning with +"x-" is marked experimental, and may be withdrawn or changed +incompatibly in a future release. + +Pragma 'name-case-whitelist' lets you violate the rules on use of +upper and lower case. Use for new code is strongly discouraged. === Downstream extensions === @@ -761,11 +711,14 @@ downstream command __com.redhat_drive-mirror. === Configuring the schema === -The 'struct', 'enum', 'union', 'alternate', 'command' and 'event' -top-level expressions can take an 'if' key. Its value must be a string -or a list of strings. A string is shorthand for a list containing just -that string. The code generated for the top-level expression will then -be guarded by #if COND for each COND in the list. +Syntax: + COND = STRING + | [ STRING, ... ] + +All definitions take an optional 'if' member. Its value must be a +string or a list of strings. A string is shorthand for a list +containing just that string. The code generated for the definition +will then be guarded by #if STRING for each STRING in the COND list. Example: a conditional struct @@ -780,29 +733,33 @@ gets its generated code guarded like this: #endif /* defined(HAVE_BAR) */ #endif /* defined(CONFIG_FOO) */ -Where a member can be defined with a single string value for its type, -it is also possible to supply a dictionary instead with both 'type' -and 'if' keys. +Individual members of complex types, commands arguments, and +event-specific data can also be made conditional. This requires the +longhand form of MEMBER. -Example: a conditional 'bar' member +Example: a struct type with unconditional member 'foo' and conditional +member 'bar' { 'struct': 'IfStruct', 'data': { 'foo': 'int', 'bar': { 'type': 'int', 'if': 'defined(IFCOND)'} } } -An enum value can be replaced by a dictionary with a 'name' and a 'if' -key. +A union's discriminator may not be conditional. + +Likewise, individual enumeration values be conditional. This requires +the longhand form of ENUM-VALUE. -Example: a conditional 'bar' enum member. +Example: an enum type with unconditional value 'foo' and conditional +value 'bar' { 'enum': 'IfEnum', 'data': [ 'foo', { 'name' : 'bar', 'if': 'defined(IFCOND)' } ] } -Similarly, features can be specified as a dictionary with a 'name' and -an 'if' key. +Likewise, features can be conditional. This requires the longhand +form of FEATURE. -Example: a conditional 'allow-negative-numbers' feature +Example: a struct with conditional feature 'allow-negative-numbers' { 'struct': 'TestType', 'data': { 'number': 'int' }, @@ -811,10 +768,162 @@ Example: a conditional 'allow-negative-numbers' feature Please note that you are responsible to ensure that the C code will compile with an arbitrary combination of conditions, since the -generators are unable to check it at this point. +generator is unable to check it at this point. + +The conditions apply to introspection as well, i.e. introspection +shows a conditional entity only when the condition is satisfied in +this particular build. + + +=== Documentation comments === + +A multi-line comment that starts and ends with a '##' line is a +documentation comment. + +If the documentation comment starts like + + ## + # @SYMBOL: + +it documents the definition if SYMBOL, else it's free-form +documentation. + +See below for more on definition documentation. + +Free-form documentation may be used to provide additional text and +structuring content. + + +==== Documentation markup ==== + +Comment text starting with '=' is a section title: + + # = Section title + +Double the '=' for a subsection title: + + # == Subsection title + +'|' denotes examples: + + # | Text of the example, may span + # | multiple lines + +'*' starts an itemized list: + + # * First item, may span + # multiple lines + # * Second item + +You can also use '-' instead of '*'. + +A decimal number followed by '.' starts a numbered list: + + # 1. First item, may span + # multiple lines + # 2. Second item + +The actual number doesn't matter. You could even use '*' instead of +'2.' for the second item. + +Lists can't be nested. Blank lines are currently not supported within +lists. + +Additional whitespace between the initial '#' and the comment text is +permitted. -The presence of 'if' keys in the schema is reflected through to the -introspection output depending on the build configuration. +*foo* and _foo_ are for strong and emphasis styles respectively (they +do not work over multiple lines). @foo is used to reference a name in +the schema. + +Example: + +## +# = Section +# == Subsection +# +# Some text foo with *strong* and _emphasis_ +# 1. with a list +# 2. like that +# +# And some code: +# | $ echo foo +# | -> do this +# | <- get that +# +## + + +==== Definition documentation ==== + +Definition documentation, if present, must immediately precede the +definition it documents. + +When documentation is required (see pragma 'doc-required'), every +definition must have documentation. + +Definition documentation starts with a line naming the definition, +followed by an optional overview, a description of each argument (for +commands and events), member (for structs and unions), branch (for +alternates), or value (for enums), and finally optional tagged +sections. + +FIXME: the parser accepts these things in almost any order. +FIXME: union branches should be described, too. + +Extensions added after the definition was first released carry a +'(since x.y.z)' comment. + +A tagged section starts with one of the following words: +"Note:"/"Notes:", "Since:", "Example"/"Examples", "Returns:", "TODO:". +The section ends with the start of a new section. + +A 'Since: x.y.z' tagged section lists the release that introduced the +definition. + +For example: + +## +# @BlockStats: +# +# Statistics of a virtual block device or a block backing device. +# +# @device: If the stats are for a virtual block device, the name +# corresponding to the virtual block device. +# +# @node-name: The node name of the device. (since 2.3) +# +# ... more members ... +# +# Since: 0.14.0 +## +{ 'struct': 'BlockStats', + 'data': {'*device': 'str', '*node-name': 'str', + ... more members ... } } + +## +# @query-blockstats: +# +# Query the @BlockStats for all virtual block devices. +# +# @query-nodes: If true, the command will query all the +# block nodes ... explain, explain ... (since 2.3) +# +# Returns: A list of @BlockStats for each virtual block devices. +# +# Since: 0.14.0 +# +# Example: +# +# -> { "execute": "query-blockstats" } +# <- { +# ... lots of output ... +# } +# +## +{ 'command': 'query-blockstats', + 'data': { '*query-nodes': 'bool' }, + 'returns': ['BlockStats'] } == Client JSON Protocol introspection == @@ -901,7 +1010,7 @@ If the event carries no additional information, "arg-type" names an object type without members. The event may not have a data member on the wire then. -Each command or event defined with dictionary-valued 'data' in the +Each command or event defined with 'data' as MEMBERS object in the QAPI schema implicitly defines an object type. Example: the SchemaInfo for EVENT_C from section Events @@ -1034,6 +1143,66 @@ the names of built-in types. Clients should examine member "json-type" instead of hard-coding names of built-in types. +== Compatibility considerations == + +Maintaining backward compatibility at the Client JSON Protocol level +while evolving the schema requires some care. This section is about +syntactic compatibility, which is necessary, but not sufficient, for +actual compatibility. + +Clients send commands with argument data, and receive command +responses with return data and events with event data. + +Adding opt-in functionality to the send direction is backwards +compatible: adding commands, optional arguments, enumeration values, +union and alternate branches; turning an argument type into an +alternate of that type; making mandatory arguments optional. Clients +oblivious of the new functionality continue to work. + +Incompatible changes include removing commands, command arguments, +enumeration values, union and alternate branches, adding mandatory +command arguments, and making optional arguments mandatory. + +The specified behavior of an absent optional argument should remain +the same. With proper documentation, this policy still allows some +flexibility; for example, when an optional 'buffer-size' argument is +specified to default to a sensible buffer size, the actual default +value can still be changed. The specified default behavior is not the +exact size of the buffer, only that the default size is sensible. + +Adding functionality to the receive direction is generally backwards +compatible: adding events, adding return and event data members. +Clients are expected to ignore the ones they don't know. + +Removing "unreachable" stuff like events that can't be triggered +anymore, optional return or event data members that can't be sent +anymore, and return or event data member (enumeration) values that +can't be sent anymore makes no difference to clients, except for +introspection. The latter can conceivably confuse clients, so tread +carefully. + +Incompatible changes include removing return and event data members. + +Any change to a command definition's 'data' or one of the types used +there (recursively) needs to consider send direction compatibility. + +Any change to a command definition's 'return', an event definition's +'data', or one of the types used there (recursively) needs to consider +receive direction compatibility. + +Any change to types used in both contexts need to consider both. + +Enumeration type values and complex and alternate type members may be +reordered freely. For enumerations and alternate types, this doesn't +affect the wire encoding. For complex types, this might make the +implementation emit JSON object members in a different order, which +the Client JSON Protocol permits. + +Since type names are not visible in the Client JSON Protocol, types +may be freely renamed. Even certain refactorings are invisible, such +as splitting members from one type into a common base type. + + == Code generation == The QAPI code generator qapi-gen.py generates code and documentation diff --git a/docs/devel/testing.rst b/docs/devel/testing.rst index bf75675fb0..8e981e062d 100644 --- a/docs/devel/testing.rst +++ b/docs/devel/testing.rst @@ -266,6 +266,8 @@ another application on the host may have locked the file, possibly leading to a test failure. If using such devices are explicitly desired, consider adding ``locking=off`` option to disable image locking. +.. _docker-ref: + Docker based tests ================== @@ -799,3 +801,77 @@ And remove any package you want with:: If you've used ``make check-acceptance``, the Python virtual environment where Avocado is installed will be cleaned up as part of ``make check-clean``. + +Testing with "make check-tcg" +============================= + +The check-tcg tests are intended for simple smoke tests of both +linux-user and softmmu TCG functionality. However to build test +programs for guest targets you need to have cross compilers available. +If your distribution supports cross compilers you can do something as +simple as:: + + apt install gcc-aarch64-linux-gnu + +The configure script will automatically pick up their presence. +Sometimes compilers have slightly odd names so the availability of +them can be prompted by passing in the appropriate configure option +for the architecture in question, for example:: + + $(configure) --cross-cc-aarch64=aarch64-cc + +There is also a ``--cross-cc-flags-ARCH`` flag in case additional +compiler flags are needed to build for a given target. + +If you have the ability to run containers as the user you can also +take advantage of the build systems "Docker" support. It will then use +containers to build any test case for an enabled guest where there is +no system compiler available. See :ref: `_docker-ref` for details. + +Running subset of tests +----------------------- + +You can build the tests for one architecture:: + + make build-tcg-tests-$TARGET + +And run with:: + + make run-tcg-tests-$TARGET + +Adding ``V=1`` to the invocation will show the details of how to +invoke QEMU for the test which is useful for debugging tests. + +TCG test dependencies +--------------------- + +The TCG tests are deliberately very light on dependencies and are +either totally bare with minimal gcc lib support (for softmmu tests) +or just glibc (for linux-user tests). This is because getting a cross +compiler to work with additional libraries can be challenging. + +Other TCG Tests +--------------- + +There are a number of out-of-tree test suites that are used for more +extensive testing of processor features. + +KVM Unit Tests +~~~~~~~~~~~~~~ + +The KVM unit tests are designed to run as a Guest OS under KVM but +there is no reason why they can't exercise the TCG as well. It +provides a minimal OS kernel with hooks for enabling the MMU as well +as reporting test results via a special device:: + + https://git.kernel.org/pub/scm/virt/kvm/kvm-unit-tests.git + +Linux Test Project +~~~~~~~~~~~~~~~~~~ + +The LTP is focused on exercising the syscall interface of a Linux +kernel. It checks that syscalls behave as documented and strives to +exercise as many corner cases as possible. It is a useful test suite +to run to exercise QEMU's linux-user code:: + + https://linux-test-project.github.io/ @@ -88,7 +88,6 @@ static MemoryRegion *system_io; AddressSpace address_space_io; AddressSpace address_space_memory; -MemoryRegion io_mem_rom, io_mem_notdirty; static MemoryRegion io_mem_unassigned; #endif @@ -191,8 +190,6 @@ typedef struct subpage_t { } subpage_t; #define PHYS_SECTION_UNASSIGNED 0 -#define PHYS_SECTION_NOTDIRTY 1 -#define PHYS_SECTION_ROM 2 static void io_mem_init(void); static void memory_map_init(void); @@ -663,7 +660,8 @@ static void tcg_register_iommu_notifier(CPUState *cpu, */ MemoryRegion *mr = MEMORY_REGION(iommu_mr); TCGIOMMUNotifier *notifier; - int i; + Error *err = NULL; + int i, ret; for (i = 0; i < cpu->iommu_notifiers->len; i++) { notifier = g_array_index(cpu->iommu_notifiers, TCGIOMMUNotifier *, i); @@ -692,7 +690,12 @@ static void tcg_register_iommu_notifier(CPUState *cpu, 0, HWADDR_MAX, iommu_idx); - memory_region_register_iommu_notifier(notifier->mr, ¬ifier->n); + ret = memory_region_register_iommu_notifier(notifier->mr, ¬ifier->n, + &err); + if (ret) { + error_report_err(err); + exit(1); + } } if (!notifier->active) { @@ -1015,7 +1018,7 @@ const char *parse_cpu_option(const char *cpu_option) void tb_invalidate_phys_addr(target_ulong addr) { mmap_lock(); - tb_invalidate_phys_page_range(addr, addr + 1, 0); + tb_invalidate_phys_page_range(addr, addr + 1); mmap_unlock(); } @@ -1042,7 +1045,7 @@ void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr, MemTxAttrs attrs) return; } ram_addr = memory_region_get_ram_addr(mr) + addr; - tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0); + tb_invalidate_phys_page_range(ram_addr, ram_addr + 1); rcu_read_unlock(); } @@ -1462,31 +1465,10 @@ bool cpu_physical_memory_snapshot_get_dirty(DirtyBitmapSnapshot *snap, /* Called from RCU critical section */ hwaddr memory_region_section_get_iotlb(CPUState *cpu, - MemoryRegionSection *section, - target_ulong vaddr, - hwaddr paddr, hwaddr xlat, - int prot, - target_ulong *address) -{ - hwaddr iotlb; - - if (memory_region_is_ram(section->mr)) { - /* Normal RAM. */ - iotlb = memory_region_get_ram_addr(section->mr) + xlat; - if (!section->readonly) { - iotlb |= PHYS_SECTION_NOTDIRTY; - } else { - iotlb |= PHYS_SECTION_ROM; - } - } else { - AddressSpaceDispatch *d; - - d = flatview_to_dispatch(section->fv); - iotlb = section - d->map.sections; - iotlb += xlat; - } - - return iotlb; + MemoryRegionSection *section) +{ + AddressSpaceDispatch *d = flatview_to_dispatch(section->fv); + return section - d->map.sections; } #endif /* defined(CONFIG_USER_ONLY) */ @@ -2742,83 +2724,6 @@ ram_addr_t qemu_ram_addr_from_host(void *ptr) return block->offset + offset; } -/* Called within RCU critical section. */ -void memory_notdirty_write_prepare(NotDirtyInfo *ndi, - CPUState *cpu, - vaddr mem_vaddr, - ram_addr_t ram_addr, - unsigned size) -{ - ndi->cpu = cpu; - ndi->ram_addr = ram_addr; - ndi->mem_vaddr = mem_vaddr; - ndi->size = size; - ndi->pages = NULL; - - assert(tcg_enabled()); - if (!cpu_physical_memory_get_dirty_flag(ram_addr, DIRTY_MEMORY_CODE)) { - ndi->pages = page_collection_lock(ram_addr, ram_addr + size); - tb_invalidate_phys_page_fast(ndi->pages, ram_addr, size); - } -} - -/* Called within RCU critical section. */ -void memory_notdirty_write_complete(NotDirtyInfo *ndi) -{ - if (ndi->pages) { - assert(tcg_enabled()); - page_collection_unlock(ndi->pages); - ndi->pages = NULL; - } - - /* Set both VGA and migration bits for simplicity and to remove - * the notdirty callback faster. - */ - cpu_physical_memory_set_dirty_range(ndi->ram_addr, ndi->size, - DIRTY_CLIENTS_NOCODE); - /* we remove the notdirty callback only if the code has been - flushed */ - if (!cpu_physical_memory_is_clean(ndi->ram_addr)) { - tlb_set_dirty(ndi->cpu, ndi->mem_vaddr); - } -} - -/* Called within RCU critical section. */ -static void notdirty_mem_write(void *opaque, hwaddr ram_addr, - uint64_t val, unsigned size) -{ - NotDirtyInfo ndi; - - memory_notdirty_write_prepare(&ndi, current_cpu, current_cpu->mem_io_vaddr, - ram_addr, size); - - stn_p(qemu_map_ram_ptr(NULL, ram_addr), size, val); - memory_notdirty_write_complete(&ndi); -} - -static bool notdirty_mem_accepts(void *opaque, hwaddr addr, - unsigned size, bool is_write, - MemTxAttrs attrs) -{ - return is_write; -} - -static const MemoryRegionOps notdirty_mem_ops = { - .write = notdirty_mem_write, - .valid.accepts = notdirty_mem_accepts, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 8, - .unaligned = false, - }, - .impl = { - .min_access_size = 1, - .max_access_size = 8, - .unaligned = false, - }, -}; - /* Generate a debug exception if a watchpoint has been hit. */ void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len, MemTxAttrs attrs, int flags, uintptr_t ra) @@ -2859,7 +2764,7 @@ void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len, cpu->watchpoint_hit = wp; mmap_lock(); - tb_check_watchpoint(cpu); + tb_check_watchpoint(cpu, ra); if (wp->flags & BP_STOP_BEFORE_ACCESS) { cpu->exception_index = EXCP_DEBUG; mmap_unlock(); @@ -2999,38 +2904,6 @@ static uint16_t dummy_section(PhysPageMap *map, FlatView *fv, MemoryRegion *mr) return phys_section_add(map, §ion); } -static void readonly_mem_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - /* Ignore any write to ROM. */ -} - -static bool readonly_mem_accepts(void *opaque, hwaddr addr, - unsigned size, bool is_write, - MemTxAttrs attrs) -{ - return is_write; -} - -/* This will only be used for writes, because reads are special cased - * to directly access the underlying host ram. - */ -static const MemoryRegionOps readonly_mem_ops = { - .write = readonly_mem_write, - .valid.accepts = readonly_mem_accepts, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 8, - .unaligned = false, - }, - .impl = { - .min_access_size = 1, - .max_access_size = 8, - .unaligned = false, - }, -}; - MemoryRegionSection *iotlb_to_section(CPUState *cpu, hwaddr index, MemTxAttrs attrs) { @@ -3044,17 +2917,8 @@ MemoryRegionSection *iotlb_to_section(CPUState *cpu, static void io_mem_init(void) { - memory_region_init_io(&io_mem_rom, NULL, &readonly_mem_ops, - NULL, NULL, UINT64_MAX); memory_region_init_io(&io_mem_unassigned, NULL, &unassigned_mem_ops, NULL, NULL, UINT64_MAX); - - /* io_mem_notdirty calls tb_invalidate_phys_page_fast, - * which can be called without the iothread mutex. - */ - memory_region_init_io(&io_mem_notdirty, NULL, ¬dirty_mem_ops, NULL, - NULL, UINT64_MAX); - memory_region_clear_global_locking(&io_mem_notdirty); } AddressSpaceDispatch *address_space_dispatch_new(FlatView *fv) @@ -3064,10 +2928,6 @@ AddressSpaceDispatch *address_space_dispatch_new(FlatView *fv) n = dummy_section(&d->map, fv, &io_mem_unassigned); assert(n == PHYS_SECTION_UNASSIGNED); - n = dummy_section(&d->map, fv, &io_mem_notdirty); - assert(n == PHYS_SECTION_NOTDIRTY); - n = dummy_section(&d->map, fv, &io_mem_rom); - assert(n == PHYS_SECTION_ROM); d->phys_map = (PhysPageEntry) { .ptr = PHYS_MAP_NODE_NIL, .skip = 1 }; @@ -3105,8 +2965,17 @@ static void tcg_log_global_after_sync(MemoryListener *listener) * by pushing the migration thread's memory read after the vCPU thread has * written the memory. */ - cpuas = container_of(listener, CPUAddressSpace, tcg_as_listener); - run_on_cpu(cpuas->cpu, do_nothing, RUN_ON_CPU_NULL); + if (replay_mode == REPLAY_MODE_NONE) { + /* + * VGA can make calls to this function while updating the screen. + * In record/replay mode this causes a deadlock, because + * run_on_cpu waits for rr mutex. Therefore no races are possible + * in this case and no need for making run_on_cpu when + * record/replay is not enabled. + */ + cpuas = container_of(listener, CPUAddressSpace, tcg_as_listener); + run_on_cpu(cpuas->cpu, do_nothing, RUN_ON_CPU_NULL); + } } static void tcg_commit(MemoryListener *listener) diff --git a/hw/arm/boot.c b/hw/arm/boot.c index bf97ef3e33..c264864c11 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -575,7 +575,7 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo, goto fail; } - if (scells < 2 && binfo->ram_size >= (1ULL << 32)) { + if (scells < 2 && binfo->ram_size >= 4 * GiB) { /* This is user error so deserves a friendlier error message * than the failure of setprop_sized_cells would provide */ @@ -754,6 +754,8 @@ static void do_cpu_reset(void *opaque) (cs != first_cpu || !info->secure_board_setup)) { /* Linux expects non-secure state */ env->cp15.scr_el3 |= SCR_NS; + /* Set NSACR.{CP11,CP10} so NS can access the FPU */ + env->cp15.nsacr |= 3 << 10; } } @@ -1095,7 +1097,7 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu, * we might still make a bad choice here. */ info->initrd_start = info->loader_start + - MIN(info->ram_size / 2, 128 * 1024 * 1024); + MIN(info->ram_size / 2, 128 * MiB); if (image_high_addr) { info->initrd_start = MAX(info->initrd_start, image_high_addr); } @@ -1155,13 +1157,13 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu, * * Let's play safe and prealign it to 2MB to give us some space. */ - align = 2 * 1024 * 1024; + align = 2 * MiB; } else { /* * Some 32bit kernels will trash anything in the 4K page the * initrd ends in, so make sure the DTB isn't caught up in that. */ - align = 4096; + align = 4 * KiB; } /* Place the DTB after the initrd in memory with alignment. */ @@ -1178,7 +1180,7 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu, info->loader_start + KERNEL_ARGS_ADDR; fixupcontext[FIXUP_ARGPTR_HI] = (info->loader_start + KERNEL_ARGS_ADDR) >> 32; - if (info->ram_size >= (1ULL << 32)) { + if (info->ram_size >= 4 * GiB) { error_report("RAM size must be less than 4GB to boot" " Linux kernel using ATAGS (try passing a device tree" " using -dtb)"); diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index db051dcac8..e2fbb8357e 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -1469,20 +1469,21 @@ static void smmuv3_class_init(ObjectClass *klass, void *data) dc->realize = smmu_realize; } -static void smmuv3_notify_flag_changed(IOMMUMemoryRegion *iommu, - IOMMUNotifierFlag old, - IOMMUNotifierFlag new) +static int smmuv3_notify_flag_changed(IOMMUMemoryRegion *iommu, + IOMMUNotifierFlag old, + IOMMUNotifierFlag new, + Error **errp) { SMMUDevice *sdev = container_of(iommu, SMMUDevice, iommu); SMMUv3State *s3 = sdev->smmu; SMMUState *s = &(s3->smmu_state); if (new & IOMMU_NOTIFIER_MAP) { - int bus_num = pci_bus_num(sdev->bus); - PCIDevice *pcidev = pci_find_device(sdev->bus, bus_num, sdev->devfn); - - warn_report("SMMUv3 does not support notification on MAP: " - "device %s will not function properly", pcidev->name); + error_setg(errp, + "device %02x.%02x.%x requires iommu MAP notifier which is " + "not currently supported", pci_bus_num(sdev->bus), + PCI_SLOT(sdev->devfn), PCI_FUNC(sdev->devfn)); + return -EINVAL; } if (old == IOMMU_NOTIFIER_NONE) { @@ -1492,6 +1493,7 @@ static void smmuv3_notify_flag_changed(IOMMUMemoryRegion *iommu, trace_smmuv3_notify_flag_del(iommu->parent_obj.name); QLIST_REMOVE(sdev, next); } + return 0; } static void smmuv3_iommu_memory_region_class_init(ObjectClass *klass, diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index f77343db60..879fc310a4 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -313,6 +313,7 @@ static void xen_block_frontend_changed(XenDevice *xendev, break; case XenbusStateClosed: + case XenbusStateUnknown: xen_block_disconnect(xendev, &local_err); if (local_err) { error_propagate(errp, local_err); diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c index 087c93e4fa..8f4d9fe472 100644 --- a/hw/char/spapr_vty.c +++ b/hw/char/spapr_vty.c @@ -5,7 +5,6 @@ #include "cpu.h" #include "migration/vmstate.h" #include "chardev/char-fe.h" -#include "hw/irq.h" #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" #include "hw/qdev-properties.h" @@ -37,7 +36,7 @@ static void vty_receive(void *opaque, const uint8_t *buf, int size) if ((dev->in == dev->out) && size) { /* toggle line to simulate edge interrupt */ - qemu_irq_pulse(spapr_vio_qirq(&dev->sdev)); + spapr_vio_irq_pulse(&dev->sdev); } for (i = 0; i < size; i++) { if (dev->in - dev->out >= VTERM_BUFSIZE) { diff --git a/hw/core/cpu.c b/hw/core/cpu.c index 0035845511..73b1ee34d0 100644 --- a/hw/core/cpu.c +++ b/hw/core/cpu.c @@ -261,7 +261,6 @@ static void cpu_common_reset(CPUState *cpu) cpu->interrupt_request = 0; cpu->halted = 0; cpu->mem_io_pc = 0; - cpu->mem_io_vaddr = 0; cpu->icount_extra = 0; atomic_set(&cpu->icount_decr_ptr->u32, 0); cpu->can_do_io = 1; diff --git a/hw/core/loader.c b/hw/core/loader.c index 0d60219364..5099f27dc8 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -1281,7 +1281,7 @@ int rom_copy(uint8_t *dest, hwaddr addr, size_t size) if (rom->addr + rom->romsize < addr) { continue; } - if (rom->addr > end) { + if (rom->addr > end || rom->addr < addr) { break; } diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index e0466ee055..ab6969b45f 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -485,6 +485,7 @@ PCIBus *dino_init(MemoryRegion *addr_space, memory_region_init_alias(&s->pci_mem_alias[i], OBJECT(s), name, &s->pci_mem, addr, DINO_MEM_CHUNK_SIZE); + g_free(name); } /* Set up PCI view of memory: Bus master address space. */ diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 2736ce835e..7e23675429 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -78,13 +78,15 @@ static void machine_hppa_init(MachineState *machine) /* Create CPUs. */ for (i = 0; i < smp_cpus; i++) { + char *name = g_strdup_printf("cpu%ld-io-eir", i); cpu[i] = HPPA_CPU(cpu_create(machine->cpu_type)); cpu_region = g_new(MemoryRegion, 1); memory_region_init_io(cpu_region, OBJECT(cpu[i]), &hppa_io_eir_ops, - cpu[i], g_strdup_printf("cpu%ld-io-eir", i), 4); + cpu[i], name, 4); memory_region_add_subregion(addr_space, CPU_HPA + i * 0x1000, cpu_region); + g_free(name); } /* Limit main memory. */ diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 08884523e2..d3726361dd 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -1466,18 +1466,21 @@ static const MemoryRegionOps mmio_mem_ops = { } }; -static void amdvi_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu, - IOMMUNotifierFlag old, - IOMMUNotifierFlag new) +static int amdvi_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu, + IOMMUNotifierFlag old, + IOMMUNotifierFlag new, + Error **errp) { AMDVIAddressSpace *as = container_of(iommu, AMDVIAddressSpace, iommu); if (new & IOMMU_NOTIFIER_MAP) { - error_report("device %02x.%02x.%x requires iommu notifier which is not " - "currently supported", as->bus_num, PCI_SLOT(as->devfn), - PCI_FUNC(as->devfn)); - exit(1); + error_setg(errp, + "device %02x.%02x.%x requires iommu notifier which is not " + "currently supported", as->bus_num, PCI_SLOT(as->devfn), + PCI_FUNC(as->devfn)); + return -EINVAL; } + return 0; } static void amdvi_init(AMDVIState *s) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index f1de8fdb75..771bed25c9 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -2929,9 +2929,10 @@ static IOMMUTLBEntry vtd_iommu_translate(IOMMUMemoryRegion *iommu, hwaddr addr, return iotlb; } -static void vtd_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu, - IOMMUNotifierFlag old, - IOMMUNotifierFlag new) +static int vtd_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu, + IOMMUNotifierFlag old, + IOMMUNotifierFlag new, + Error **errp) { VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu); IntelIOMMUState *s = vtd_as->iommu_state; @@ -2944,6 +2945,7 @@ static void vtd_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu, } else if (new == IOMMU_NOTIFIER_NONE) { QLIST_REMOVE(vtd_as, next); } + return 0; } static int vtd_post_load(void *opaque, int version_id) diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c index f3ccd11c79..19984d2af9 100644 --- a/hw/ide/cmd646.c +++ b/hw/ide/cmd646.c @@ -300,6 +300,7 @@ static void pci_cmd646_ide_realize(PCIDevice *dev, Error **errp) d->bmdma[i].bus = &d->bus[i]; ide_register_restart_cb(&d->bus[i]); } + g_free(irq); vmstate_register(DEVICE(dev), 0, &vmstate_ide_pci, d); qemu_register_reset(cmd646_reset, d); diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index c1c97192a7..04879abf2e 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -528,12 +528,15 @@ static void spapr_xive_register_types(void) type_init(spapr_xive_register_types) -bool spapr_xive_irq_claim(SpaprXive *xive, uint32_t lisn, bool lsi) +int spapr_xive_irq_claim(SpaprXive *xive, int lisn, bool lsi, Error **errp) { XiveSource *xsrc = &xive->source; - if (lisn >= xive->nr_irqs) { - return false; + assert(lisn < xive->nr_irqs); + + if (xive_eas_is_valid(&xive->eat[lisn])) { + error_setg(errp, "IRQ %d is not free", lisn); + return -EBUSY; } /* @@ -545,26 +548,17 @@ bool spapr_xive_irq_claim(SpaprXive *xive, uint32_t lisn, bool lsi) } if (kvm_irqchip_in_kernel()) { - Error *local_err = NULL; - - kvmppc_xive_source_reset_one(xsrc, lisn, &local_err); - if (local_err) { - error_report_err(local_err); - return false; - } + return kvmppc_xive_source_reset_one(xsrc, lisn, errp); } - return true; + return 0; } -bool spapr_xive_irq_free(SpaprXive *xive, uint32_t lisn) +void spapr_xive_irq_free(SpaprXive *xive, int lisn) { - if (lisn >= xive->nr_irqs) { - return false; - } + assert(lisn < xive->nr_irqs); xive->eat[lisn].w &= cpu_to_be64(~EAS_VALID); - return true; } /* diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c index 17af4d19f5..51b334b676 100644 --- a/hw/intc/spapr_xive_kvm.c +++ b/hw/intc/spapr_xive_kvm.c @@ -232,14 +232,14 @@ void kvmppc_xive_sync_source(SpaprXive *xive, uint32_t lisn, Error **errp) * only need to inform the KVM XIVE device about their type: LSI or * MSI. */ -void kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp) +int kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp) { SpaprXive *xive = SPAPR_XIVE(xsrc->xive); uint64_t state = 0; /* The KVM XIVE device is not in use */ if (xive->fd == -1) { - return; + return -ENODEV; } if (xive_source_irq_is_lsi(xsrc, srcno)) { @@ -249,17 +249,22 @@ void kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp) } } - kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_SOURCE, srcno, &state, - true, errp); + return kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_SOURCE, srcno, &state, + true, errp); } static void kvmppc_xive_source_reset(XiveSource *xsrc, Error **errp) { + SpaprXive *xive = SPAPR_XIVE(xsrc->xive); int i; for (i = 0; i < xsrc->nr_irqs; i++) { Error *local_err = NULL; + if (!xive_eas_is_valid(&xive->eat[i])) { + continue; + } + kvmppc_xive_source_reset_one(xsrc, i, &local_err); if (local_err) { error_propagate(errp, local_err); @@ -328,11 +333,18 @@ uint64_t kvmppc_xive_esb_rw(XiveSource *xsrc, int srcno, uint32_t offset, static void kvmppc_xive_source_get_state(XiveSource *xsrc) { + SpaprXive *xive = SPAPR_XIVE(xsrc->xive); int i; for (i = 0; i < xsrc->nr_irqs; i++) { + uint8_t pq; + + if (!xive_eas_is_valid(&xive->eat[i])) { + continue; + } + /* Perform a load without side effect to retrieve the PQ bits */ - uint8_t pq = xive_esb_read(xsrc, i, XIVE_ESB_GET); + pq = xive_esb_read(xsrc, i, XIVE_ESB_GET); /* and save PQ locally */ xive_source_esb_set(xsrc, i, pq); @@ -521,9 +533,14 @@ static void kvmppc_xive_change_state_handler(void *opaque, int running, */ if (running) { for (i = 0; i < xsrc->nr_irqs; i++) { - uint8_t pq = xive_source_esb_get(xsrc, i); + uint8_t pq; uint8_t old_pq; + if (!xive_eas_is_valid(&xive->eat[i])) { + continue; + } + + pq = xive_source_esb_get(xsrc, i); old_pq = xive_esb_read(xsrc, i, XIVE_ESB_SET_PQ_00 + (pq << 8)); /* @@ -545,7 +562,13 @@ static void kvmppc_xive_change_state_handler(void *opaque, int running, * migration is in progress. */ for (i = 0; i < xsrc->nr_irqs; i++) { - uint8_t pq = xive_esb_read(xsrc, i, XIVE_ESB_GET); + uint8_t pq; + + if (!xive_eas_is_valid(&xive->eat[i])) { + continue; + } + + pq = xive_esb_read(xsrc, i, XIVE_ESB_GET); /* * PQ is set to PENDING to possibly catch a triggered @@ -655,6 +678,17 @@ int kvmppc_xive_post_load(SpaprXive *xive, int version_id) continue; } + /* + * We can only restore the source config if the source has been + * previously set in KVM. Since we don't do that for all interrupts + * at reset time anymore, let's do it now. + */ + kvmppc_xive_source_reset_one(&xive->source, i, &local_err); + if (local_err) { + error_report_err(local_err); + return -1; + } + kvmppc_xive_set_source_config(xive, i, &xive->eat[i], &local_err); if (local_err) { error_report_err(local_err); diff --git a/hw/intc/trace-events b/hw/intc/trace-events index 719f46b516..527c3f76ca 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -66,12 +66,12 @@ xics_icp_accept(uint32_t old_xirr, uint32_t new_xirr) "icp_accept: XIRR 0x%"PRIx xics_icp_eoi(int server, uint32_t xirr, uint32_t new_xirr) "icp_eoi: server %d given XIRR 0x%"PRIx32" new XIRR 0x%"PRIx32 xics_icp_irq(int server, int nr, uint8_t priority) "cpu %d trying to deliver irq 0x%"PRIx32" priority 0x%x" xics_icp_raise(uint32_t xirr, uint8_t pending_priority) "raising IRQ new XIRR=0x%x new pending priority=0x%x" -xics_ics_simple_set_irq_msi(int srcno, int nr) "set_irq_msi: srcno %d [irq 0x%x]" +xics_ics_set_irq_msi(int srcno, int nr) "set_irq_msi: srcno %d [irq 0x%x]" xics_masked_pending(void) "set_irq_msi: masked pending" -xics_ics_simple_set_irq_lsi(int srcno, int nr) "set_irq_lsi: srcno %d [irq 0x%x]" -xics_ics_simple_write_xive(int nr, int srcno, int server, uint8_t priority) "ics_write_xive: irq 0x%x [src %d] server 0x%x prio 0x%x" -xics_ics_simple_reject(int nr, int srcno) "reject irq 0x%x [src %d]" -xics_ics_simple_eoi(int nr) "ics_eoi: irq 0x%x" +xics_ics_set_irq_lsi(int srcno, int nr) "set_irq_lsi: srcno %d [irq 0x%x]" +xics_ics_write_xive(int nr, int srcno, int server, uint8_t priority) "ics_write_xive: irq 0x%x [src %d] server 0x%x prio 0x%x" +xics_ics_reject(int nr, int srcno) "reject irq 0x%x [src %d]" +xics_ics_eoi(int nr) "ics_eoi: irq 0x%x" # s390_flic_kvm.c flic_create_device(int err) "flic: create device failed %d" diff --git a/hw/intc/xics.c b/hw/intc/xics.c index b2fca2975c..dfe7dbd254 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -98,32 +98,8 @@ void ics_pic_print_info(ICSState *ics, Monitor *mon) #define XISR(icp) (((icp)->xirr) & XISR_MASK) #define CPPR(icp) (((icp)->xirr) >> 24) -static void ics_reject(ICSState *ics, uint32_t nr) -{ - ICSStateClass *k = ICS_BASE_GET_CLASS(ics); - - if (k->reject) { - k->reject(ics, nr); - } -} - -void ics_resend(ICSState *ics) -{ - ICSStateClass *k = ICS_BASE_GET_CLASS(ics); - - if (k->resend) { - k->resend(ics); - } -} - -static void ics_eoi(ICSState *ics, int nr) -{ - ICSStateClass *k = ICS_BASE_GET_CLASS(ics); - - if (k->eoi) { - k->eoi(ics, nr); - } -} +static void ics_reject(ICSState *ics, uint32_t nr); +static void ics_eoi(ICSState *ics, uint32_t nr); static void icp_check_ipi(ICPState *icp) { @@ -427,7 +403,7 @@ Object *icp_create(Object *cpu, const char *type, XICSFabric *xi, Error **errp) /* * ICS: Source layer */ -static void ics_simple_resend_msi(ICSState *ics, int srcno) +static void ics_resend_msi(ICSState *ics, int srcno) { ICSIRQState *irq = ics->irqs + srcno; @@ -440,7 +416,7 @@ static void ics_simple_resend_msi(ICSState *ics, int srcno) } } -static void ics_simple_resend_lsi(ICSState *ics, int srcno) +static void ics_resend_lsi(ICSState *ics, int srcno) { ICSIRQState *irq = ics->irqs + srcno; @@ -452,11 +428,11 @@ static void ics_simple_resend_lsi(ICSState *ics, int srcno) } } -static void ics_simple_set_irq_msi(ICSState *ics, int srcno, int val) +static void ics_set_irq_msi(ICSState *ics, int srcno, int val) { ICSIRQState *irq = ics->irqs + srcno; - trace_xics_ics_simple_set_irq_msi(srcno, srcno + ics->offset); + trace_xics_ics_set_irq_msi(srcno, srcno + ics->offset); if (val) { if (irq->priority == 0xff) { @@ -468,20 +444,20 @@ static void ics_simple_set_irq_msi(ICSState *ics, int srcno, int val) } } -static void ics_simple_set_irq_lsi(ICSState *ics, int srcno, int val) +static void ics_set_irq_lsi(ICSState *ics, int srcno, int val) { ICSIRQState *irq = ics->irqs + srcno; - trace_xics_ics_simple_set_irq_lsi(srcno, srcno + ics->offset); + trace_xics_ics_set_irq_lsi(srcno, srcno + ics->offset); if (val) { irq->status |= XICS_STATUS_ASSERTED; } else { irq->status &= ~XICS_STATUS_ASSERTED; } - ics_simple_resend_lsi(ics, srcno); + ics_resend_lsi(ics, srcno); } -void ics_simple_set_irq(void *opaque, int srcno, int val) +void ics_set_irq(void *opaque, int srcno, int val) { ICSState *ics = (ICSState *)opaque; @@ -491,13 +467,13 @@ void ics_simple_set_irq(void *opaque, int srcno, int val) } if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) { - ics_simple_set_irq_lsi(ics, srcno, val); + ics_set_irq_lsi(ics, srcno, val); } else { - ics_simple_set_irq_msi(ics, srcno, val); + ics_set_irq_msi(ics, srcno, val); } } -static void ics_simple_write_xive_msi(ICSState *ics, int srcno) +static void ics_write_xive_msi(ICSState *ics, int srcno) { ICSIRQState *irq = ics->irqs + srcno; @@ -510,13 +486,13 @@ static void ics_simple_write_xive_msi(ICSState *ics, int srcno) icp_irq(ics, irq->server, srcno + ics->offset, irq->priority); } -static void ics_simple_write_xive_lsi(ICSState *ics, int srcno) +static void ics_write_xive_lsi(ICSState *ics, int srcno) { - ics_simple_resend_lsi(ics, srcno); + ics_resend_lsi(ics, srcno); } -void ics_simple_write_xive(ICSState *ics, int srcno, int server, - uint8_t priority, uint8_t saved_priority) +void ics_write_xive(ICSState *ics, int srcno, int server, + uint8_t priority, uint8_t saved_priority) { ICSIRQState *irq = ics->irqs + srcno; @@ -524,21 +500,20 @@ void ics_simple_write_xive(ICSState *ics, int srcno, int server, irq->priority = priority; irq->saved_priority = saved_priority; - trace_xics_ics_simple_write_xive(ics->offset + srcno, srcno, server, - priority); + trace_xics_ics_write_xive(ics->offset + srcno, srcno, server, priority); if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) { - ics_simple_write_xive_lsi(ics, srcno); + ics_write_xive_lsi(ics, srcno); } else { - ics_simple_write_xive_msi(ics, srcno); + ics_write_xive_msi(ics, srcno); } } -static void ics_simple_reject(ICSState *ics, uint32_t nr) +static void ics_reject(ICSState *ics, uint32_t nr) { ICSIRQState *irq = ics->irqs + nr - ics->offset; - trace_xics_ics_simple_reject(nr, nr - ics->offset); + trace_xics_ics_reject(nr, nr - ics->offset); if (irq->flags & XICS_FLAGS_IRQ_MSI) { irq->status |= XICS_STATUS_REJECTED; } else if (irq->flags & XICS_FLAGS_IRQ_LSI) { @@ -546,100 +521,41 @@ static void ics_simple_reject(ICSState *ics, uint32_t nr) } } -static void ics_simple_resend(ICSState *ics) +void ics_resend(ICSState *ics) { int i; for (i = 0; i < ics->nr_irqs; i++) { /* FIXME: filter by server#? */ if (ics->irqs[i].flags & XICS_FLAGS_IRQ_LSI) { - ics_simple_resend_lsi(ics, i); + ics_resend_lsi(ics, i); } else { - ics_simple_resend_msi(ics, i); + ics_resend_msi(ics, i); } } } -static void ics_simple_eoi(ICSState *ics, uint32_t nr) +static void ics_eoi(ICSState *ics, uint32_t nr) { int srcno = nr - ics->offset; ICSIRQState *irq = ics->irqs + srcno; - trace_xics_ics_simple_eoi(nr); + trace_xics_ics_eoi(nr); if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) { irq->status &= ~XICS_STATUS_SENT; } } -static void ics_simple_reset(DeviceState *dev) -{ - ICSStateClass *icsc = ICS_BASE_GET_CLASS(dev); - - icsc->parent_reset(dev); - - if (kvm_irqchip_in_kernel()) { - Error *local_err = NULL; - - ics_set_kvm_state(ICS_BASE(dev), &local_err); - if (local_err) { - error_report_err(local_err); - } - } -} - -static void ics_simple_reset_handler(void *dev) -{ - ics_simple_reset(dev); -} - -static void ics_simple_realize(DeviceState *dev, Error **errp) -{ - ICSState *ics = ICS_SIMPLE(dev); - ICSStateClass *icsc = ICS_BASE_GET_CLASS(ics); - Error *local_err = NULL; - - icsc->parent_realize(dev, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - qemu_register_reset(ics_simple_reset_handler, ics); -} - -static void ics_simple_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - ICSStateClass *isc = ICS_BASE_CLASS(klass); - - device_class_set_parent_realize(dc, ics_simple_realize, - &isc->parent_realize); - device_class_set_parent_reset(dc, ics_simple_reset, - &isc->parent_reset); - - isc->reject = ics_simple_reject; - isc->resend = ics_simple_resend; - isc->eoi = ics_simple_eoi; -} - -static const TypeInfo ics_simple_info = { - .name = TYPE_ICS_SIMPLE, - .parent = TYPE_ICS_BASE, - .instance_size = sizeof(ICSState), - .class_init = ics_simple_class_init, - .class_size = sizeof(ICSStateClass), -}; - static void ics_reset_irq(ICSIRQState *irq) { irq->priority = 0xff; irq->saved_priority = 0xff; } -static void ics_base_reset(DeviceState *dev) +static void ics_reset(DeviceState *dev) { - ICSState *ics = ICS_BASE(dev); + ICSState *ics = ICS(dev); int i; uint8_t flags[ics->nr_irqs]; @@ -653,17 +569,31 @@ static void ics_base_reset(DeviceState *dev) ics_reset_irq(ics->irqs + i); ics->irqs[i].flags = flags[i]; } + + if (kvm_irqchip_in_kernel()) { + Error *local_err = NULL; + + ics_set_kvm_state(ICS(dev), &local_err); + if (local_err) { + error_report_err(local_err); + } + } +} + +static void ics_reset_handler(void *dev) +{ + ics_reset(dev); } -static void ics_base_realize(DeviceState *dev, Error **errp) +static void ics_realize(DeviceState *dev, Error **errp) { - ICSState *ics = ICS_BASE(dev); + ICSState *ics = ICS(dev); + Error *local_err = NULL; Object *obj; - Error *err = NULL; - obj = object_property_get_link(OBJECT(dev), ICS_PROP_XICS, &err); + obj = object_property_get_link(OBJECT(dev), ICS_PROP_XICS, &local_err); if (!obj) { - error_propagate_prepend(errp, err, + error_propagate_prepend(errp, local_err, "required link '" ICS_PROP_XICS "' not found: "); return; @@ -675,16 +605,18 @@ static void ics_base_realize(DeviceState *dev, Error **errp) return; } ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState)); + + qemu_register_reset(ics_reset_handler, ics); } -static void ics_base_instance_init(Object *obj) +static void ics_instance_init(Object *obj) { - ICSState *ics = ICS_BASE(obj); + ICSState *ics = ICS(obj); ics->offset = XICS_IRQ_BASE; } -static int ics_base_pre_save(void *opaque) +static int ics_pre_save(void *opaque) { ICSState *ics = opaque; @@ -695,7 +627,7 @@ static int ics_base_pre_save(void *opaque) return 0; } -static int ics_base_post_load(void *opaque, int version_id) +static int ics_post_load(void *opaque, int version_id) { ICSState *ics = opaque; @@ -713,7 +645,7 @@ static int ics_base_post_load(void *opaque, int version_id) return 0; } -static const VMStateDescription vmstate_ics_base_irq = { +static const VMStateDescription vmstate_ics_irq = { .name = "ics/irq", .version_id = 2, .minimum_version_id = 1, @@ -727,45 +659,44 @@ static const VMStateDescription vmstate_ics_base_irq = { }, }; -static const VMStateDescription vmstate_ics_base = { +static const VMStateDescription vmstate_ics = { .name = "ics", .version_id = 1, .minimum_version_id = 1, - .pre_save = ics_base_pre_save, - .post_load = ics_base_post_load, + .pre_save = ics_pre_save, + .post_load = ics_post_load, .fields = (VMStateField[]) { /* Sanity check */ VMSTATE_UINT32_EQUAL(nr_irqs, ICSState, NULL), VMSTATE_STRUCT_VARRAY_POINTER_UINT32(irqs, ICSState, nr_irqs, - vmstate_ics_base_irq, + vmstate_ics_irq, ICSIRQState), VMSTATE_END_OF_LIST() }, }; -static Property ics_base_properties[] = { +static Property ics_properties[] = { DEFINE_PROP_UINT32("nr-irqs", ICSState, nr_irqs, 0), DEFINE_PROP_END_OF_LIST(), }; -static void ics_base_class_init(ObjectClass *klass, void *data) +static void ics_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - dc->realize = ics_base_realize; - dc->props = ics_base_properties; - dc->reset = ics_base_reset; - dc->vmsd = &vmstate_ics_base; + dc->realize = ics_realize; + dc->props = ics_properties; + dc->reset = ics_reset; + dc->vmsd = &vmstate_ics; } -static const TypeInfo ics_base_info = { - .name = TYPE_ICS_BASE, +static const TypeInfo ics_info = { + .name = TYPE_ICS, .parent = TYPE_DEVICE, - .abstract = true, .instance_size = sizeof(ICSState), - .instance_init = ics_base_instance_init, - .class_init = ics_base_class_init, + .instance_init = ics_instance_init, + .class_init = ics_class_init, .class_size = sizeof(ICSStateClass), }; @@ -805,8 +736,7 @@ void ics_set_irq_type(ICSState *ics, int srcno, bool lsi) static void xics_register_types(void) { - type_register_static(&ics_simple_info); - type_register_static(&ics_base_info); + type_register_static(&ics_info); type_register_static(&icp_info); type_register_static(&xics_fabric_info); } diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index a4d2e876cc..ba90d6dc96 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -190,6 +190,10 @@ void ics_get_kvm_state(ICSState *ics) for (i = 0; i < ics->nr_irqs; i++) { ICSIRQState *irq = &ics->irqs[i]; + if (ics_irq_free(ics, i)) { + continue; + } + kvm_device_access(kernel_xics_fd, KVM_DEV_XICS_GRP_SOURCES, i + ics->offset, &state, false, &error_fatal); @@ -301,6 +305,10 @@ int ics_set_kvm_state(ICSState *ics, Error **errp) Error *local_err = NULL; int ret; + if (ics_irq_free(ics, i)) { + continue; + } + ret = ics_set_kvm_state_one(ics, i, &local_err); if (ret < 0) { error_propagate(errp, local_err); diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c index 6577be0d92..6e5eb24b3c 100644 --- a/hw/intc/xics_spapr.c +++ b/hw/intc/xics_spapr.c @@ -179,7 +179,7 @@ static void rtas_set_xive(PowerPCCPU *cpu, SpaprMachineState *spapr, } srcno = nr - ics->offset; - ics_simple_write_xive(ics, srcno, server, priority, priority); + ics_write_xive(ics, srcno, server, priority, priority); rtas_st(rets, 0, RTAS_OUT_SUCCESS); } @@ -243,8 +243,8 @@ static void rtas_int_off(PowerPCCPU *cpu, SpaprMachineState *spapr, } srcno = nr - ics->offset; - ics_simple_write_xive(ics, srcno, ics->irqs[srcno].server, 0xff, - ics->irqs[srcno].priority); + ics_write_xive(ics, srcno, ics->irqs[srcno].server, 0xff, + ics->irqs[srcno].priority); rtas_st(rets, 0, RTAS_OUT_SUCCESS); } @@ -276,15 +276,25 @@ static void rtas_int_on(PowerPCCPU *cpu, SpaprMachineState *spapr, } srcno = nr - ics->offset; - ics_simple_write_xive(ics, srcno, ics->irqs[srcno].server, - ics->irqs[srcno].saved_priority, - ics->irqs[srcno].saved_priority); + ics_write_xive(ics, srcno, ics->irqs[srcno].server, + ics->irqs[srcno].saved_priority, + ics->irqs[srcno].saved_priority); rtas_st(rets, 0, RTAS_OUT_SUCCESS); } -void xics_spapr_init(SpaprMachineState *spapr) +static void ics_spapr_realize(DeviceState *dev, Error **errp) { + ICSState *ics = ICS_SPAPR(dev); + ICSStateClass *icsc = ICS_GET_CLASS(ics); + Error *local_err = NULL; + + icsc->parent_realize(dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_set_xive); spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_get_xive); spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_int_off); @@ -306,7 +316,7 @@ void spapr_dt_xics(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt, }; int node; - _FDT(node = fdt_add_subnode(fdt, 0, XICS_NODENAME)); + _FDT(node = fdt_add_subnode(fdt, 0, "interrupt-controller")); _FDT(fdt_setprop_string(fdt, node, "device_type", "PowerPC-External-Interrupt-Presentation")); @@ -319,3 +329,25 @@ void spapr_dt_xics(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt, _FDT(fdt_setprop_cell(fdt, node, "linux,phandle", phandle)); _FDT(fdt_setprop_cell(fdt, node, "phandle", phandle)); } + +static void ics_spapr_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ICSStateClass *isc = ICS_CLASS(klass); + + device_class_set_parent_realize(dc, ics_spapr_realize, + &isc->parent_realize); +} + +static const TypeInfo ics_spapr_info = { + .name = TYPE_ICS_SPAPR, + .parent = TYPE_ICS, + .class_init = ics_spapr_class_init, +}; + +static void xics_spapr_register_types(void) +{ + type_register_static(&ics_spapr_info); +} + +type_init(xics_spapr_register_types) diff --git a/hw/intc/xive.c b/hw/intc/xive.c index b7417210d8..29df06df11 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -1397,6 +1397,14 @@ static bool xive_presenter_match(XiveRouter *xrtr, uint8_t format, int ring; /* + * Skip partially initialized vCPUs. This can happen when + * vCPUs are hotplugged. + */ + if (!tctx) { + continue; + } + + /* * HW checks that the CPU is enabled in the Physical Thread * Enable Register (PTER). */ diff --git a/hw/isa/Kconfig b/hw/isa/Kconfig index 6db0d7970c..98a289957e 100644 --- a/hw/isa/Kconfig +++ b/hw/isa/Kconfig @@ -13,9 +13,13 @@ config I82378 select MC146818RTC select PCSPK -config PC87312 +config ISA_SUPERIO bool select ISA_BUS + +config PC87312 + bool + select ISA_SUPERIO select I8259 select I8254 select I8257 @@ -34,14 +38,14 @@ config PIIX4 config VT82C686 bool - select ISA_BUS + select ISA_SUPERIO select ACPI_SMBUS select SERIAL_ISA select FDC config SMC37C669 bool - select ISA_BUS + select ISA_SUPERIO select SERIAL_ISA select PARALLEL select FDC diff --git a/hw/isa/Makefile.objs b/hw/isa/Makefile.objs index 9e106df186..ff97485504 100644 --- a/hw/isa/Makefile.objs +++ b/hw/isa/Makefile.objs @@ -1,5 +1,5 @@ common-obj-$(CONFIG_ISA_BUS) += isa-bus.o -common-obj-$(CONFIG_ISA_BUS) += isa-superio.o +common-obj-$(CONFIG_ISA_SUPERIO) += isa-superio.o common-obj-$(CONFIG_APM) += apm.o common-obj-$(CONFIG_I82378) += i82378.o common-obj-$(CONFIG_PC87312) += pc87312.o diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c index 012710d057..60c5802b4e 100644 --- a/hw/m68k/mcf5208.c +++ b/hw/m68k/mcf5208.c @@ -273,6 +273,8 @@ static void mcf5208evb_init(MachineState *machine) 0xfc030000, pic + 36); } + g_free(pic); + /* 0xfc000000 SCM. */ /* 0xfc004000 XBS. */ /* 0xfc008000 FlexBus CS. */ diff --git a/hw/m68k/next-cube.c b/hw/m68k/next-cube.c index 9a4a7328f9..e5343348d0 100644 --- a/hw/m68k/next-cube.c +++ b/hw/m68k/next-cube.c @@ -60,6 +60,15 @@ typedef struct next_dma { uint32_t size; } next_dma; +typedef struct NextRtc { + uint8_t ram[32]; + uint8_t command; + uint8_t value; + uint8_t status; + uint8_t control; + uint8_t retval; +} NextRtc; + typedef struct { MachineState parent; @@ -77,7 +86,7 @@ typedef struct { uint32_t scr1; uint32_t scr2; - uint8_t rtc_ram[32]; + NextRtc rtc; } NeXTState; /* Thanks to NeXT forums for this */ @@ -105,11 +114,8 @@ static void nextscr2_write(NeXTState *s, uint32_t val, int size) static int led; static int phase; static uint8_t old_scr2; - static uint8_t rtc_command; - static uint8_t rtc_value; - static uint8_t rtc_status = 0x90; - static uint8_t rtc_return; uint8_t scr2_2; + NextRtc *rtc = &s->rtc; if (size == 4) { scr2_2 = (val >> 8) & 0xFF; @@ -135,52 +141,52 @@ static void nextscr2_write(NeXTState *s, uint32_t val, int size) if (((old_scr2 & SCR2_RTCLK) != (scr2_2 & SCR2_RTCLK)) && ((scr2_2 & SCR2_RTCLK) == 0)) { if (phase < 8) { - rtc_command = (rtc_command << 1) | - ((scr2_2 & SCR2_RTDATA) ? 1 : 0); + rtc->command = (rtc->command << 1) | + ((scr2_2 & SCR2_RTDATA) ? 1 : 0); } if (phase >= 8 && phase < 16) { - rtc_value = (rtc_value << 1) | ((scr2_2 & SCR2_RTDATA) ? 1 : 0); + rtc->value = (rtc->value << 1) | + ((scr2_2 & SCR2_RTDATA) ? 1 : 0); /* if we read RAM register, output RT_DATA bit */ - if (rtc_command <= 0x1F) { + if (rtc->command <= 0x1F) { scr2_2 = scr2_2 & (~SCR2_RTDATA); - if (s->rtc_ram[rtc_command] & (0x80 >> (phase - 8))) { + if (rtc->ram[rtc->command] & (0x80 >> (phase - 8))) { scr2_2 |= SCR2_RTDATA; } - rtc_return = (rtc_return << 1) | - ((scr2_2 & SCR2_RTDATA) ? 1 : 0); + rtc->retval = (rtc->retval << 1) | + ((scr2_2 & SCR2_RTDATA) ? 1 : 0); } /* read the status 0x30 */ - if (rtc_command == 0x30) { + if (rtc->command == 0x30) { scr2_2 = scr2_2 & (~SCR2_RTDATA); /* for now status = 0x98 (new rtc + FTU) */ - if (rtc_status & (0x80 >> (phase - 8))) { + if (rtc->status & (0x80 >> (phase - 8))) { scr2_2 |= SCR2_RTDATA; } - rtc_return = (rtc_return << 1) | - ((scr2_2 & SCR2_RTDATA) ? 1 : 0); + rtc->retval = (rtc->retval << 1) | + ((scr2_2 & SCR2_RTDATA) ? 1 : 0); } /* read the status 0x31 */ - if (rtc_command == 0x31) { + if (rtc->command == 0x31) { scr2_2 = scr2_2 & (~SCR2_RTDATA); - /* for now 0x00 */ - if (0x00 & (0x80 >> (phase - 8))) { + if (rtc->control & (0x80 >> (phase - 8))) { scr2_2 |= SCR2_RTDATA; } - rtc_return = (rtc_return << 1) | - ((scr2_2 & SCR2_RTDATA) ? 1 : 0); + rtc->retval = (rtc->retval << 1) | + ((scr2_2 & SCR2_RTDATA) ? 1 : 0); } - if ((rtc_command >= 0x20) && (rtc_command <= 0x2F)) { + if ((rtc->command >= 0x20) && (rtc->command <= 0x2F)) { scr2_2 = scr2_2 & (~SCR2_RTDATA); /* for now 0x00 */ time_t time_h = time(NULL); struct tm *info = localtime(&time_h); int ret = 0; - switch (rtc_command) { + switch (rtc->command) { case 0x20: ret = SCR2_TOBCD(info->tm_sec); break; @@ -205,22 +211,22 @@ static void nextscr2_write(NeXTState *s, uint32_t val, int size) if (ret & (0x80 >> (phase - 8))) { scr2_2 |= SCR2_RTDATA; } - rtc_return = (rtc_return << 1) | - ((scr2_2 & SCR2_RTDATA) ? 1 : 0); + rtc->retval = (rtc->retval << 1) | + ((scr2_2 & SCR2_RTDATA) ? 1 : 0); } } phase++; if (phase == 16) { - if (rtc_command >= 0x80 && rtc_command <= 0x9F) { - s->rtc_ram[rtc_command - 0x80] = rtc_value; + if (rtc->command >= 0x80 && rtc->command <= 0x9F) { + rtc->ram[rtc->command - 0x80] = rtc->value; } /* write to x30 register */ - if (rtc_command == 0xB1) { + if (rtc->command == 0xB1) { /* clear FTU */ - if (rtc_value & 0x04) { - rtc_status = rtc_status & (~0x18); + if (rtc->value & 0x04) { + rtc->status = rtc->status & (~0x18); s->int_status = s->int_status & (~0x04); } } @@ -229,8 +235,8 @@ static void nextscr2_write(NeXTState *s, uint32_t val, int size) } else { /* else end or abort */ phase = -1; - rtc_command = 0; - rtc_value = 0; + rtc->command = 0; + rtc->value = 0; } s->scr2 = val & 0xFFFF00FF; s->scr2 |= scr2_2 << 8; @@ -881,9 +887,10 @@ static void next_cube_init(MachineState *machine) /* 0x0000XX00 << vital bits */ ns->scr1 = 0x00011102; ns->scr2 = 0x00ff0c80; + ns->rtc.status = 0x90; /* Load RTC RAM - TODO: provide possibility to load contents from file */ - memcpy(ns->rtc_ram, rtc_ram2, 32); + memcpy(ns->rtc.ram, rtc_ram2, 32); /* 64MB RAM starting at 0x04000000 */ memory_region_allocate_system_memory(ram, NULL, "next.ram", ram_size); diff --git a/hw/microblaze/boot.c b/hw/microblaze/boot.c index bade4d22c0..d1d7dfbbb9 100644 --- a/hw/microblaze/boot.c +++ b/hw/microblaze/boot.c @@ -100,6 +100,7 @@ static int microblaze_load_dtb(hwaddr addr, } cpu_physical_memory_write(addr, fdt, fdt_size); + g_free(fdt); return fdt_size; } diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig index 62aa01b29e..2c2adbc42a 100644 --- a/hw/mips/Kconfig +++ b/hw/mips/Kconfig @@ -13,6 +13,7 @@ config R4K config MALTA bool + select ISA_SUPERIO config MIPSSIM bool diff --git a/hw/mips/mips_int.c b/hw/mips/mips_int.c index 5ebc9618a7..863ed45659 100644 --- a/hw/mips/mips_int.c +++ b/hw/mips/mips_int.c @@ -81,6 +81,7 @@ void cpu_mips_irq_init_cpu(MIPSCPU *cpu) for (i = 0; i < 8; i++) { env->irq[i] = qi[i]; } + g_free(qi); } void cpu_mips_soft_irq(CPUMIPSState *env, int irq, int level) diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c index c967b97d80..8d010a0b6e 100644 --- a/hw/mips/mips_jazz.c +++ b/hw/mips/mips_jazz.c @@ -362,6 +362,8 @@ static void mips_jazz_init(MachineState *machine, /* LED indicator */ sysbus_create_simple("jazz-led", 0x8000f000, NULL); + + g_free(dmas); } static diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c index 701e6e1514..3d96884d66 100644 --- a/hw/net/spapr_llan.c +++ b/hw/net/spapr_llan.c @@ -27,7 +27,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "hw/irq.h" #include "qemu/log.h" #include "qemu/module.h" #include "net/net.h" @@ -267,7 +266,7 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf, } if (sdev->signal_state & 1) { - qemu_irq_pulse(spapr_vio_qirq(sdev)); + spapr_vio_irq_pulse(sdev); } return size; diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index 2c4e1c8de0..580bb4f0dd 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -9,6 +9,7 @@ obj-$(CONFIG_PSERIES) += spapr_tpm_proxy.o obj-$(CONFIG_SPAPR_RNG) += spapr_rng.o # IBM PowerNV obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o pnv_core.o pnv_lpc.o pnv_psi.o pnv_occ.o pnv_bmc.o +obj-$(CONFIG_POWERNV) += pnv_homer.o ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy) obj-y += spapr_pci_vfio.o spapr_pci_nvlink2.o endif diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 3f08db7b9e..7cf64b6d25 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -187,7 +187,8 @@ static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt) _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq))); _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq))); - _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->slb_size))); + _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", + cpu->hash64_opts->slb_size))); _FDT((fdt_setprop_string(fdt, offset, "status", "okay"))); _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0))); @@ -200,19 +201,23 @@ static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt) segs, sizeof(segs)))); } - /* Advertise VMX/VSX (vector extensions) if available + /* + * Advertise VMX/VSX (vector extensions) if available * 0 / no property == no vector extensions * 1 == VMX / Altivec available - * 2 == VSX available */ + * 2 == VSX available + */ if (env->insns_flags & PPC_ALTIVEC) { uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1; _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx))); } - /* Advertise DFP (Decimal Floating Point) if available + /* + * Advertise DFP (Decimal Floating Point) if available * 0 / no property == no DFP - * 1 == DFP available */ + * 1 == DFP available + */ if (env->insns_flags2 & PPC2_DFP) { _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1))); } @@ -424,7 +429,8 @@ static int pnv_dt_isa_device(DeviceState *dev, void *opaque) return 0; } -/* The default LPC bus of a multichip system is on chip 0. It's +/* + * The default LPC bus of a multichip system is on chip 0. It's * recognized by the firmware (skiboot) using a "primary" property. */ static void pnv_dt_isa(PnvMachineState *pnv, void *fdt) @@ -442,8 +448,10 @@ static void pnv_dt_isa(PnvMachineState *pnv, void *fdt) assert(phandle > 0); _FDT((fdt_setprop_cell(fdt, isa_offset, "phandle", phandle))); - /* ISA devices are not necessarily parented to the ISA bus so we - * can not use object_child_foreach() */ + /* + * ISA devices are not necessarily parented to the ISA bus so we + * can not use object_child_foreach() + */ qbus_walk_children(BUS(pnv->isa_bus), pnv_dt_isa_device, NULL, NULL, NULL, &args); } @@ -545,7 +553,8 @@ static void pnv_reset(MachineState *machine) qemu_devices_reset(); - /* OpenPOWER systems have a BMC, which can be defined on the + /* + * OpenPOWER systems have a BMC, which can be defined on the * command line with: * * -device ipmi-bmc-sim,id=bmc0 @@ -705,7 +714,8 @@ static void pnv_init(MachineState *machine) pnv->chips[i] = PNV_CHIP(chip); - /* TODO: put all the memory in one node on chip 0 until we find a + /* + * TODO: put all the memory in one node on chip 0 until we find a * way to specify different ranges for each chip */ if (i == 0) { @@ -732,8 +742,10 @@ static void pnv_init(MachineState *machine) /* Create an RTC ISA device too */ mc146818_rtc_init(pnv->isa_bus, 2000, NULL); - /* OpenPOWER systems use a IPMI SEL Event message to notify the - * host to powerdown */ + /* + * OpenPOWER systems use a IPMI SEL Event message to notify the + * host to powerdown + */ pnv->powerdown_notifier.notify = pnv_powerdown_notify; qemu_register_powerdown_notifier(&pnv->powerdown_notifier); } @@ -803,7 +815,8 @@ static void pnv_chip_power9_intc_create(PnvChip *chip, PowerPCCPU *cpu, pnv_cpu->intc = obj; } -/* Allowed core identifiers on a POWER8 Processor Chip : +/* + * Allowed core identifiers on a POWER8 Processor Chip : * * <EX0 reserved> * EX1 - Venice only @@ -847,6 +860,11 @@ static void pnv_chip_power8_instance_init(Object *obj) TYPE_PNV8_OCC, &error_abort, NULL); object_property_add_const_link(OBJECT(&chip8->occ), "psi", OBJECT(&chip8->psi), &error_abort); + + object_initialize_child(obj, "homer", &chip8->homer, sizeof(chip8->homer), + TYPE_PNV8_HOMER, &error_abort, NULL); + object_property_add_const_link(OBJECT(&chip8->homer), "chip", obj, + &error_abort); } static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp) @@ -923,8 +941,10 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) (uint64_t) PNV_XSCOM_BASE(chip), PNV_XSCOM_LPC_BASE); - /* Interrupt Management Area. This is the memory region holding - * all the Interrupt Control Presenter (ICP) registers */ + /* + * Interrupt Management Area. This is the memory region holding + * all the Interrupt Control Presenter (ICP) registers + */ pnv_chip_icp_realize(chip8, &local_err); if (local_err) { error_propagate(errp, local_err); @@ -938,6 +958,20 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp) return; } pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip8->occ.xscom_regs); + + /* OCC SRAM model */ + memory_region_add_subregion(get_system_memory(), PNV_OCC_COMMON_AREA(chip), + &chip8->occ.sram_regs); + + /* HOMER */ + object_property_set_bool(OBJECT(&chip8->homer), true, "realized", + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + memory_region_add_subregion(get_system_memory(), PNV_HOMER_BASE(chip), + &chip8->homer.regs); } static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data) @@ -1020,6 +1054,11 @@ static void pnv_chip_power9_instance_init(Object *obj) TYPE_PNV9_OCC, &error_abort, NULL); object_property_add_const_link(OBJECT(&chip9->occ), "psi", OBJECT(&chip9->psi), &error_abort); + + object_initialize_child(obj, "homer", &chip9->homer, sizeof(chip9->homer), + TYPE_PNV9_HOMER, &error_abort, NULL); + object_property_add_const_link(OBJECT(&chip9->homer), "chip", obj, + &error_abort); } static void pnv_chip_quad_realize(Pnv9Chip *chip9, Error **errp) @@ -1126,6 +1165,20 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp) return; } pnv_xscom_add_subregion(chip, PNV9_XSCOM_OCC_BASE, &chip9->occ.xscom_regs); + + /* OCC SRAM model */ + memory_region_add_subregion(get_system_memory(), PNV9_OCC_COMMON_AREA(chip), + &chip9->occ.sram_regs); + + /* HOMER */ + object_property_set_bool(OBJECT(&chip9->homer), true, "realized", + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + memory_region_add_subregion(get_system_memory(), PNV9_HOMER_BASE(chip), + &chip9->homer.regs); } static void pnv_chip_power9_class_init(ObjectClass *klass, void *data) @@ -1404,8 +1457,8 @@ static void pnv_machine_class_init(ObjectClass *oc, void *data) mc->init = pnv_init; mc->reset = pnv_reset; mc->max_cpus = MAX_CPUS; - mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for - * storage */ + /* Pnv provides a AHCI device for storage */ + mc->block_default_type = IF_IDE; mc->no_parallel = 1; mc->default_boot_order = NULL; /* @@ -1432,23 +1485,21 @@ static void pnv_machine_class_init(ObjectClass *oc, void *data) .parent = TYPE_PNV9_CHIP, \ } -#define DEFINE_PNV_MACHINE_TYPE(cpu, class_initfn) \ - { \ - .name = MACHINE_TYPE_NAME(cpu), \ - .parent = TYPE_PNV_MACHINE, \ - .instance_size = sizeof(PnvMachineState), \ - .instance_init = pnv_machine_instance_init, \ - .class_init = class_initfn, \ - .interfaces = (InterfaceInfo[]) { \ - { TYPE_XICS_FABRIC }, \ - { TYPE_INTERRUPT_STATS_PROVIDER }, \ - { }, \ - }, \ - } - static const TypeInfo types[] = { - DEFINE_PNV_MACHINE_TYPE("powernv8", pnv_machine_power8_class_init), - DEFINE_PNV_MACHINE_TYPE("powernv9", pnv_machine_power9_class_init), + { + .name = MACHINE_TYPE_NAME("powernv9"), + .parent = TYPE_PNV_MACHINE, + .class_init = pnv_machine_power9_class_init, + }, + { + .name = MACHINE_TYPE_NAME("powernv8"), + .parent = TYPE_PNV_MACHINE, + .class_init = pnv_machine_power8_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_XICS_FABRIC }, + { }, + }, + }, { .name = TYPE_PNV_MACHINE, .parent = TYPE_MACHINE, @@ -1457,7 +1508,6 @@ static const TypeInfo types[] = { .instance_init = pnv_machine_instance_init, .class_init = pnv_machine_class_init, .interfaces = (InterfaceInfo[]) { - { TYPE_XICS_FABRIC }, { TYPE_INTERRUPT_STATS_PROVIDER }, { }, }, diff --git a/hw/ppc/pnv_bmc.c b/hw/ppc/pnv_bmc.c index e5eb6e5a70..dc5e918cb7 100644 --- a/hw/ppc/pnv_bmc.c +++ b/hw/ppc/pnv_bmc.c @@ -77,13 +77,10 @@ void pnv_dt_bmc_sensors(IPMIBmc *bmc, void *fdt) const struct ipmi_sdr_compact *sdr; uint16_t nextrec; - offset = fdt_add_subnode(fdt, 0, "/bmc"); + offset = fdt_add_subnode(fdt, 0, "bmc"); _FDT(offset); _FDT((fdt_setprop_string(fdt, offset, "name", "bmc"))); - _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 0x1))); - _FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 0x0))); - offset = fdt_add_subnode(fdt, offset, "sensors"); _FDT(offset); diff --git a/hw/ppc/pnv_homer.c b/hw/ppc/pnv_homer.c new file mode 100644 index 0000000000..cc881a3b32 --- /dev/null +++ b/hw/ppc/pnv_homer.c @@ -0,0 +1,272 @@ +/* + * QEMU PowerPC PowerNV Emulation of a few HOMER related registers + * + * Copyright (c) 2019, IBM Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "exec/hwaddr.h" +#include "exec/memory.h" +#include "sysemu/cpus.h" +#include "hw/qdev-core.h" +#include "hw/ppc/pnv.h" +#include "hw/ppc/pnv_homer.h" + + +static bool core_max_array(PnvHomer *homer, hwaddr addr) +{ + int i; + PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer); + + for (i = 0; i <= homer->chip->nr_cores; i++) { + if (addr == (hmrc->core_max_base + i)) { + return true; + } + } + return false; +} + +/* P8 Pstate table */ + +#define PNV8_OCC_PSTATE_VERSION 0x1f8001 +#define PNV8_OCC_PSTATE_MIN 0x1f8003 +#define PNV8_OCC_PSTATE_VALID 0x1f8000 +#define PNV8_OCC_PSTATE_THROTTLE 0x1f8002 +#define PNV8_OCC_PSTATE_NOM 0x1f8004 +#define PNV8_OCC_PSTATE_TURBO 0x1f8005 +#define PNV8_OCC_PSTATE_ULTRA_TURBO 0x1f8006 +#define PNV8_OCC_PSTATE_DATA 0x1f8008 +#define PNV8_OCC_PSTATE_ID_ZERO 0x1f8010 +#define PNV8_OCC_PSTATE_ID_ONE 0x1f8018 +#define PNV8_OCC_PSTATE_ID_TWO 0x1f8020 +#define PNV8_OCC_VDD_VOLTAGE_IDENTIFIER 0x1f8012 +#define PNV8_OCC_VCS_VOLTAGE_IDENTIFIER 0x1f8013 +#define PNV8_OCC_PSTATE_ZERO_FREQUENCY 0x1f8014 +#define PNV8_OCC_PSTATE_ONE_FREQUENCY 0x1f801c +#define PNV8_OCC_PSTATE_TWO_FREQUENCY 0x1f8024 +#define PNV8_CORE_MAX_BASE 0x1f8810 + + +static uint64_t pnv_power8_homer_read(void *opaque, hwaddr addr, + unsigned size) +{ + PnvHomer *homer = PNV_HOMER(opaque); + + switch (addr) { + case PNV8_OCC_PSTATE_VERSION: + case PNV8_OCC_PSTATE_MIN: + case PNV8_OCC_PSTATE_ID_ZERO: + return 0; + case PNV8_OCC_PSTATE_VALID: + case PNV8_OCC_PSTATE_THROTTLE: + case PNV8_OCC_PSTATE_NOM: + case PNV8_OCC_PSTATE_TURBO: + case PNV8_OCC_PSTATE_ID_ONE: + case PNV8_OCC_VDD_VOLTAGE_IDENTIFIER: + case PNV8_OCC_VCS_VOLTAGE_IDENTIFIER: + return 1; + case PNV8_OCC_PSTATE_ULTRA_TURBO: + case PNV8_OCC_PSTATE_ID_TWO: + return 2; + case PNV8_OCC_PSTATE_DATA: + return 0x1000000000000000; + /* P8 frequency for 0, 1, and 2 pstates */ + case PNV8_OCC_PSTATE_ZERO_FREQUENCY: + case PNV8_OCC_PSTATE_ONE_FREQUENCY: + case PNV8_OCC_PSTATE_TWO_FREQUENCY: + return 3000; + } + /* pstate table core max array */ + if (core_max_array(homer, addr)) { + return 1; + } + return 0; +} + +static void pnv_power8_homer_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + /* callback function defined to homer write */ + return; +} + +static const MemoryRegionOps pnv_power8_homer_ops = { + .read = pnv_power8_homer_read, + .write = pnv_power8_homer_write, + .valid.min_access_size = 1, + .valid.max_access_size = 8, + .impl.min_access_size = 1, + .impl.max_access_size = 8, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static void pnv_homer_power8_class_init(ObjectClass *klass, void *data) +{ + PnvHomerClass *homer = PNV_HOMER_CLASS(klass); + + homer->homer_size = PNV_HOMER_SIZE; + homer->homer_ops = &pnv_power8_homer_ops; + homer->core_max_base = PNV8_CORE_MAX_BASE; +} + +static const TypeInfo pnv_homer_power8_type_info = { + .name = TYPE_PNV8_HOMER, + .parent = TYPE_PNV_HOMER, + .instance_size = sizeof(PnvHomer), + .class_init = pnv_homer_power8_class_init, +}; + +/* P9 Pstate table */ + +#define PNV9_OCC_PSTATE_ID_ZERO 0xe2018 +#define PNV9_OCC_PSTATE_ID_ONE 0xe2020 +#define PNV9_OCC_PSTATE_ID_TWO 0xe2028 +#define PNV9_OCC_PSTATE_DATA 0xe2000 +#define PNV9_OCC_PSTATE_DATA_AREA 0xe2008 +#define PNV9_OCC_PSTATE_MIN 0xe2003 +#define PNV9_OCC_PSTATE_NOM 0xe2004 +#define PNV9_OCC_PSTATE_TURBO 0xe2005 +#define PNV9_OCC_PSTATE_ULTRA_TURBO 0xe2818 +#define PNV9_OCC_MAX_PSTATE_ULTRA_TURBO 0xe2006 +#define PNV9_OCC_PSTATE_MAJOR_VERSION 0xe2001 +#define PNV9_OCC_OPAL_RUNTIME_DATA 0xe2b85 +#define PNV9_CHIP_HOMER_IMAGE_POINTER 0x200008 +#define PNV9_CHIP_HOMER_BASE 0x0 +#define PNV9_OCC_PSTATE_ZERO_FREQUENCY 0xe201c +#define PNV9_OCC_PSTATE_ONE_FREQUENCY 0xe2024 +#define PNV9_OCC_PSTATE_TWO_FREQUENCY 0xe202c +#define PNV9_OCC_ROLE_MASTER_OR_SLAVE 0xe2002 +#define PNV9_CORE_MAX_BASE 0xe2819 + + +static uint64_t pnv_power9_homer_read(void *opaque, hwaddr addr, + unsigned size) +{ + PnvHomer *homer = PNV_HOMER(opaque); + + switch (addr) { + case PNV9_OCC_MAX_PSTATE_ULTRA_TURBO: + case PNV9_OCC_PSTATE_ID_ZERO: + return 0; + case PNV9_OCC_PSTATE_DATA: + case PNV9_OCC_ROLE_MASTER_OR_SLAVE: + case PNV9_OCC_PSTATE_NOM: + case PNV9_OCC_PSTATE_TURBO: + case PNV9_OCC_PSTATE_ID_ONE: + case PNV9_OCC_PSTATE_ULTRA_TURBO: + case PNV9_OCC_OPAL_RUNTIME_DATA: + return 1; + case PNV9_OCC_PSTATE_MIN: + case PNV9_OCC_PSTATE_ID_TWO: + return 2; + + /* 3000 khz frequency for 0, 1, and 2 pstates */ + case PNV9_OCC_PSTATE_ZERO_FREQUENCY: + case PNV9_OCC_PSTATE_ONE_FREQUENCY: + case PNV9_OCC_PSTATE_TWO_FREQUENCY: + return 3000; + case PNV9_OCC_PSTATE_MAJOR_VERSION: + return 0x90; + case PNV9_CHIP_HOMER_BASE: + case PNV9_OCC_PSTATE_DATA_AREA: + case PNV9_CHIP_HOMER_IMAGE_POINTER: + return 0x1000000000000000; + } + /* pstate table core max array */ + if (core_max_array(homer, addr)) { + return 1; + } + return 0; +} + +static void pnv_power9_homer_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + /* callback function defined to homer write */ + return; +} + +static const MemoryRegionOps pnv_power9_homer_ops = { + .read = pnv_power9_homer_read, + .write = pnv_power9_homer_write, + .valid.min_access_size = 1, + .valid.max_access_size = 8, + .impl.min_access_size = 1, + .impl.max_access_size = 8, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static void pnv_homer_power9_class_init(ObjectClass *klass, void *data) +{ + PnvHomerClass *homer = PNV_HOMER_CLASS(klass); + + homer->homer_size = PNV9_HOMER_SIZE; + homer->homer_ops = &pnv_power9_homer_ops; + homer->core_max_base = PNV9_CORE_MAX_BASE; +} + +static const TypeInfo pnv_homer_power9_type_info = { + .name = TYPE_PNV9_HOMER, + .parent = TYPE_PNV_HOMER, + .instance_size = sizeof(PnvHomer), + .class_init = pnv_homer_power9_class_init, +}; + +static void pnv_homer_realize(DeviceState *dev, Error **errp) +{ + PnvHomer *homer = PNV_HOMER(dev); + PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer); + Object *obj; + Error *local_err = NULL; + + obj = object_property_get_link(OBJECT(dev), "chip", &local_err); + if (!obj) { + error_propagate(errp, local_err); + error_prepend(errp, "required link 'chip' not found: "); + return; + } + homer->chip = PNV_CHIP(obj); + /* homer region */ + memory_region_init_io(&homer->regs, OBJECT(dev), + hmrc->homer_ops, homer, "homer-main-memory", + hmrc->homer_size); +} + +static void pnv_homer_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = pnv_homer_realize; + dc->desc = "PowerNV HOMER Memory"; +} + +static const TypeInfo pnv_homer_type_info = { + .name = TYPE_PNV_HOMER, + .parent = TYPE_DEVICE, + .instance_size = sizeof(PnvHomer), + .class_init = pnv_homer_class_init, + .class_size = sizeof(PnvHomerClass), + .abstract = true, +}; + +static void pnv_homer_register_types(void) +{ + type_register_static(&pnv_homer_type_info); + type_register_static(&pnv_homer_power8_type_info); + type_register_static(&pnv_homer_power9_type_info); +} + +type_init(pnv_homer_register_types); diff --git a/hw/ppc/pnv_occ.c b/hw/ppc/pnv_occ.c index 8bead2c930..785653bb67 100644 --- a/hw/ppc/pnv_occ.c +++ b/hw/ppc/pnv_occ.c @@ -30,6 +30,24 @@ #define OCB_OCI_OCCMISC_AND 0x4021 #define OCB_OCI_OCCMISC_OR 0x4022 +/* OCC sensors */ +#define OCC_SENSOR_DATA_BLOCK_OFFSET 0x580000 +#define OCC_SENSOR_DATA_VALID 0x580001 +#define OCC_SENSOR_DATA_VERSION 0x580002 +#define OCC_SENSOR_DATA_READING_VERSION 0x580004 +#define OCC_SENSOR_DATA_NR_SENSORS 0x580008 +#define OCC_SENSOR_DATA_NAMES_OFFSET 0x580010 +#define OCC_SENSOR_DATA_READING_PING_OFFSET 0x580014 +#define OCC_SENSOR_DATA_READING_PONG_OFFSET 0x58000c +#define OCC_SENSOR_DATA_NAME_LENGTH 0x58000d +#define OCC_SENSOR_NAME_STRUCTURE_TYPE 0x580023 +#define OCC_SENSOR_LOC_CORE 0x580022 +#define OCC_SENSOR_LOC_GPU 0x580020 +#define OCC_SENSOR_TYPE_POWER 0x580003 +#define OCC_SENSOR_NAME 0x580005 +#define HWMON_SENSORS_MASK 0x58001e +#define SLW_IMAGE_BASE 0x0 + static void pnv_occ_set_misc(PnvOCC *occ, uint64_t val) { bool irq_state; @@ -82,6 +100,48 @@ static void pnv_occ_power8_xscom_write(void *opaque, hwaddr addr, } } +static uint64_t pnv_occ_common_area_read(void *opaque, hwaddr addr, + unsigned width) +{ + switch (addr) { + /* + * occ-sensor sanity check that asserts the sensor + * header block + */ + case OCC_SENSOR_DATA_BLOCK_OFFSET: + case OCC_SENSOR_DATA_VALID: + case OCC_SENSOR_DATA_VERSION: + case OCC_SENSOR_DATA_READING_VERSION: + case OCC_SENSOR_DATA_NR_SENSORS: + case OCC_SENSOR_DATA_NAMES_OFFSET: + case OCC_SENSOR_DATA_READING_PING_OFFSET: + case OCC_SENSOR_DATA_READING_PONG_OFFSET: + case OCC_SENSOR_NAME_STRUCTURE_TYPE: + return 1; + case OCC_SENSOR_DATA_NAME_LENGTH: + return 0x30; + case OCC_SENSOR_LOC_CORE: + return 0x0040; + case OCC_SENSOR_TYPE_POWER: + return 0x0080; + case OCC_SENSOR_NAME: + return 0x1000; + case HWMON_SENSORS_MASK: + case OCC_SENSOR_LOC_GPU: + return 0x8e00; + case SLW_IMAGE_BASE: + return 0x1000000000000000; + } + return 0; +} + +static void pnv_occ_common_area_write(void *opaque, hwaddr addr, + uint64_t val, unsigned width) +{ + /* callback function defined to occ common area write */ + return; +} + static const MemoryRegionOps pnv_occ_power8_xscom_ops = { .read = pnv_occ_power8_xscom_read, .write = pnv_occ_power8_xscom_write, @@ -92,12 +152,24 @@ static const MemoryRegionOps pnv_occ_power8_xscom_ops = { .endianness = DEVICE_BIG_ENDIAN, }; +const MemoryRegionOps pnv_occ_sram_ops = { + .read = pnv_occ_common_area_read, + .write = pnv_occ_common_area_write, + .valid.min_access_size = 1, + .valid.max_access_size = 8, + .impl.min_access_size = 1, + .impl.max_access_size = 8, + .endianness = DEVICE_BIG_ENDIAN, +}; + static void pnv_occ_power8_class_init(ObjectClass *klass, void *data) { PnvOCCClass *poc = PNV_OCC_CLASS(klass); poc->xscom_size = PNV_XSCOM_OCC_SIZE; + poc->sram_size = PNV_OCC_COMMON_AREA_SIZE; poc->xscom_ops = &pnv_occ_power8_xscom_ops; + poc->sram_ops = &pnv_occ_sram_ops; poc->psi_irq = PSIHB_IRQ_OCC; } @@ -168,7 +240,9 @@ static void pnv_occ_power9_class_init(ObjectClass *klass, void *data) PnvOCCClass *poc = PNV_OCC_CLASS(klass); poc->xscom_size = PNV9_XSCOM_OCC_SIZE; + poc->sram_size = PNV9_OCC_COMMON_AREA_SIZE; poc->xscom_ops = &pnv_occ_power9_xscom_ops; + poc->sram_ops = &pnv_occ_sram_ops; poc->psi_irq = PSIHB9_IRQ_OCC; } @@ -199,6 +273,10 @@ static void pnv_occ_realize(DeviceState *dev, Error **errp) /* XScom region for OCC registers */ pnv_xscom_region_init(&occ->xscom_regs, OBJECT(dev), poc->xscom_ops, occ, "xscom-occ", poc->xscom_size); + + /* XScom region for OCC SRAM registers */ + pnv_xscom_region_init(&occ->sram_regs, OBJECT(dev), poc->sram_ops, + occ, "occ-common-area", poc->sram_size); } static void pnv_occ_class_init(ObjectClass *klass, void *data) diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index 88ba8e7b9b..a997f16bb4 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -311,7 +311,7 @@ static void pnv_psi_set_xivr(PnvPsi *psi, uint32_t reg, uint64_t val) * do for now but a more accurate implementation would instead * use a fixed server/prio and a remapper of the generated irq. */ - ics_simple_write_xive(ics, src, server, prio, prio); + ics_write_xive(ics, src, server, prio, prio); } static uint64_t pnv_psi_reg_read(PnvPsi *psi, uint32_t offset, bool mmio) @@ -469,7 +469,7 @@ static void pnv_psi_power8_instance_init(Object *obj) Pnv8Psi *psi8 = PNV8_PSI(obj); object_initialize_child(obj, "ics-psi", &psi8->ics, sizeof(psi8->ics), - TYPE_ICS_SIMPLE, &error_abort, NULL); + TYPE_ICS, &error_abort, NULL); } static const uint8_t irq_to_xivr[] = { @@ -514,7 +514,7 @@ static void pnv_psi_power8_realize(DeviceState *dev, Error **errp) ics_set_irq_type(ics, i, true); } - psi->qirqs = qemu_allocate_irqs(ics_simple_set_irq, ics, ics->nr_irqs); + psi->qirqs = qemu_allocate_irqs(ics_set_irq, ics, ics->nr_irqs); /* XSCOM region for PSI registers */ pnv_xscom_region_init(&psi->xscom_regs, OBJECT(dev), &pnv_psi_xscom_ops, diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c index 67aab98fef..f01d788a65 100644 --- a/hw/ppc/pnv_xscom.c +++ b/hw/ppc/pnv_xscom.c @@ -36,6 +36,16 @@ #define PRD_P9_IPOLL_REG_MASK 0x000F0033 #define PRD_P9_IPOLL_REG_STATUS 0x000F0034 +/* PBA BARs */ +#define P8_PBA_BAR0 0x2013f00 +#define P8_PBA_BAR2 0x2013f02 +#define P8_PBA_BARMASK0 0x2013f04 +#define P8_PBA_BARMASK2 0x2013f06 +#define P9_PBA_BAR0 0x5012b00 +#define P9_PBA_BAR2 0x5012b02 +#define P9_PBA_BARMASK0 0x5012b04 +#define P9_PBA_BARMASK2 0x5012b06 + static void xscom_complete(CPUState *cs, uint64_t hmer_bits) { /* @@ -74,6 +84,26 @@ static uint64_t xscom_read_default(PnvChip *chip, uint32_t pcba) case 0x18002: /* ECID2 */ return 0; + case P9_PBA_BAR0: + return PNV9_HOMER_BASE(chip); + case P8_PBA_BAR0: + return PNV_HOMER_BASE(chip); + + case P9_PBA_BARMASK0: /* P9 homer region size */ + return PNV9_HOMER_SIZE; + case P8_PBA_BARMASK0: /* P8 homer region size */ + return PNV_HOMER_SIZE; + + case P9_PBA_BAR2: /* P9 occ common area */ + return PNV9_OCC_COMMON_AREA(chip); + case P8_PBA_BAR2: /* P8 occ common area */ + return PNV_OCC_COMMON_AREA(chip); + + case P9_PBA_BARMASK2: /* P9 occ common area size */ + return PNV9_OCC_COMMON_AREA_SIZE; + case P8_PBA_BARMASK2: /* P8 occ common area size */ + return PNV_OCC_COMMON_AREA_SIZE; + case 0x1010c00: /* PIBAM FIR */ case 0x1010c03: /* PIBAM FIR MASK */ @@ -93,13 +123,9 @@ static uint64_t xscom_read_default(PnvChip *chip, uint32_t pcba) case 0x2020009: /* ADU stuff, error register */ case 0x202000f: /* ADU stuff, receive status register*/ return 0; - case 0x2013f00: /* PBA stuff */ case 0x2013f01: /* PBA stuff */ - case 0x2013f02: /* PBA stuff */ case 0x2013f03: /* PBA stuff */ - case 0x2013f04: /* PBA stuff */ case 0x2013f05: /* PBA stuff */ - case 0x2013f06: /* PBA stuff */ case 0x2013f07: /* PBA stuff */ return 0; case 0x2013028: /* CAPP stuff */ diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 08a2a5a770..514a17ae74 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -81,6 +81,8 @@ #include "hw/mem/memory-device.h" #include "hw/ppc/spapr_tpm_proxy.h" +#include "monitor/monitor.h" + #include <libfdt.h> /* SLOF memory layout: @@ -94,7 +96,6 @@ * We load our kernel at 4M, leaving space for SLOF initial image */ #define FDT_MAX_SIZE 0x100000 -#define RTAS_MAX_SIZE 0x10000 #define RTAS_MAX_ADDR 0x80000000 /* RTAS must stay below that */ #define FW_MAX_SIZE 0x400000 #define FW_FILE_NAME "slof.bin" @@ -218,8 +219,7 @@ static int spapr_fixup_cpu_numa_dt(void *fdt, int offset, PowerPCCPU *cpu) /* Populate the "ibm,pa-features" property */ static void spapr_populate_pa_features(SpaprMachineState *spapr, PowerPCCPU *cpu, - void *fdt, int offset, - bool legacy_guest) + void *fdt, int offset) { uint8_t pa_features_206[] = { 6, 0, 0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 }; @@ -285,7 +285,7 @@ static void spapr_populate_pa_features(SpaprMachineState *spapr, if ((spapr_get_cap(spapr, SPAPR_CAP_HTM) != 0) && pa_size > 24) { pa_features[24] |= 0x80; /* Transactional memory support */ } - if (legacy_guest && pa_size > 40) { + if (spapr->cas_pre_isa3_guest && pa_size > 40) { /* Workaround for broken kernels that attempt (guest) radix * mode when they can't handle it, if they see the radix bit set * in pa-features. So hide it from them. */ @@ -295,65 +295,6 @@ static void spapr_populate_pa_features(SpaprMachineState *spapr, _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size))); } -static int spapr_fixup_cpu_dt(void *fdt, SpaprMachineState *spapr) -{ - MachineState *ms = MACHINE(spapr); - int ret = 0, offset, cpus_offset; - CPUState *cs; - char cpu_model[32]; - uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)}; - - CPU_FOREACH(cs) { - PowerPCCPU *cpu = POWERPC_CPU(cs); - DeviceClass *dc = DEVICE_GET_CLASS(cs); - int index = spapr_get_vcpu_id(cpu); - int compat_smt = MIN(ms->smp.threads, ppc_compat_max_vthreads(cpu)); - - if (!spapr_is_thread0_in_vcore(spapr, cpu)) { - continue; - } - - snprintf(cpu_model, 32, "%s@%x", dc->fw_name, index); - - cpus_offset = fdt_path_offset(fdt, "/cpus"); - if (cpus_offset < 0) { - cpus_offset = fdt_add_subnode(fdt, 0, "cpus"); - if (cpus_offset < 0) { - return cpus_offset; - } - } - offset = fdt_subnode_offset(fdt, cpus_offset, cpu_model); - if (offset < 0) { - offset = fdt_add_subnode(fdt, cpus_offset, cpu_model); - if (offset < 0) { - return offset; - } - } - - ret = fdt_setprop(fdt, offset, "ibm,pft-size", - pft_size_prop, sizeof(pft_size_prop)); - if (ret < 0) { - return ret; - } - - if (ms->numa_state->num_nodes > 1) { - ret = spapr_fixup_cpu_numa_dt(fdt, offset, cpu); - if (ret < 0) { - return ret; - } - } - - ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt); - if (ret < 0) { - return ret; - } - - spapr_populate_pa_features(spapr, cpu, fdt, offset, - spapr->cas_legacy_guest_workaround); - } - return ret; -} - static hwaddr spapr_node0_size(MachineState *machine) { if (machine->numa_state->num_nodes) { @@ -388,7 +329,7 @@ static int spapr_populate_memory_node(void *fdt, int nodeid, hwaddr start, mem_reg_property[0] = cpu_to_be64(start); mem_reg_property[1] = cpu_to_be64(size); - sprintf(mem_name, "memory@" TARGET_FMT_lx, start); + sprintf(mem_name, "memory@%" HWADDR_PRIx, start); off = fdt_add_subnode(fdt, 0, mem_name); _FDT(off); _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); @@ -551,7 +492,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, page_sizes_prop, page_sizes_prop_size))); } - spapr_populate_pa_features(spapr, cpu, fdt, offset, false); + spapr_populate_pa_features(spapr, cpu, fdt, offset); _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", cs->cpu_index / vcpus_per_socket))); @@ -984,11 +925,13 @@ static bool spapr_hotplugged_dev_before_cas(void) return false; } +static void *spapr_build_fdt(SpaprMachineState *spapr); + int spapr_h_cas_compose_response(SpaprMachineState *spapr, target_ulong addr, target_ulong size, SpaprOptionVector *ov5_updates) { - void *fdt, *fdt_skel; + void *fdt; SpaprDeviceTreeUpdateHeader hdr = { .version_id = 1 }; if (spapr_hotplugged_dev_before_cas()) { @@ -1004,28 +947,11 @@ int spapr_h_cas_compose_response(SpaprMachineState *spapr, size -= sizeof(hdr); - /* Create skeleton */ - fdt_skel = g_malloc0(size); - _FDT((fdt_create(fdt_skel, size))); - _FDT((fdt_finish_reservemap(fdt_skel))); - _FDT((fdt_begin_node(fdt_skel, ""))); - _FDT((fdt_end_node(fdt_skel))); - _FDT((fdt_finish(fdt_skel))); - fdt = g_malloc0(size); - _FDT((fdt_open_into(fdt_skel, fdt, size))); - g_free(fdt_skel); - - /* Fixup cpu nodes */ - _FDT((spapr_fixup_cpu_dt(fdt, spapr))); - - if (spapr_dt_cas_updates(spapr, fdt, ov5_updates)) { - return -1; - } - - /* Pack resulting tree */ + fdt = spapr_build_fdt(spapr); _FDT((fdt_pack(fdt))); if (fdt_totalsize(fdt) + sizeof(hdr) > size) { + g_free(fdt); trace_spapr_cas_failed(size); return -1; } @@ -1033,7 +959,11 @@ int spapr_h_cas_compose_response(SpaprMachineState *spapr, cpu_physical_memory_write(addr, &hdr, sizeof(hdr)); cpu_physical_memory_write(addr + sizeof(hdr), fdt, fdt_totalsize(fdt)); trace_spapr_cas_continue(fdt_totalsize(fdt) + sizeof(hdr)); - g_free(fdt); + + g_free(spapr->fdt_blob); + spapr->fdt_size = fdt_totalsize(fdt); + spapr->fdt_initial_size = spapr->fdt_size; + spapr->fdt_blob = fdt; return 0; } @@ -1136,19 +1066,28 @@ static void spapr_dt_ov5_platform_support(SpaprMachineState *spapr, void *fdt, PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); char val[2 * 4] = { - 23, spapr->irq->ov5, /* Xive mode. */ + 23, 0x00, /* XICS / XIVE mode */ 24, 0x00, /* Hash/Radix, filled in below. */ 25, 0x00, /* Hash options: Segment Tables == no, GTSE == no. */ 26, 0x40, /* Radix options: GTSE == yes. */ }; + if (spapr->irq->xics && spapr->irq->xive) { + val[1] = SPAPR_OV5_XIVE_BOTH; + } else if (spapr->irq->xive) { + val[1] = SPAPR_OV5_XIVE_EXPLOIT; + } else { + assert(spapr->irq->xics); + val[1] = SPAPR_OV5_XIVE_LEGACY; + } + if (!ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0, first_ppc_cpu->compat_pvr)) { /* * If we're in a pre POWER9 compat mode then the guest should * do hash and use the legacy interrupt mode */ - val[1] = 0x00; /* XICS */ + val[1] = SPAPR_OV5_XIVE_LEGACY; /* XICS */ val[3] = 0x00; /* Hash */ } else if (kvm_enabled()) { if (kvmppc_has_cap_mmu_radix() && kvmppc_has_cap_mmu_hash_v3()) { @@ -1178,11 +1117,16 @@ static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt) _FDT(chosen = fdt_add_subnode(fdt, 0, "chosen")); - _FDT(fdt_setprop_string(fdt, chosen, "bootargs", machine->kernel_cmdline)); - _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-start", - spapr->initrd_base)); - _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-end", - spapr->initrd_base + spapr->initrd_size)); + if (machine->kernel_cmdline && machine->kernel_cmdline[0]) { + _FDT(fdt_setprop_string(fdt, chosen, "bootargs", + machine->kernel_cmdline)); + } + if (spapr->initrd_size) { + _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-start", + spapr->initrd_base)); + _FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-end", + spapr->initrd_base + spapr->initrd_size)); + } if (spapr->kernel_size) { uint64_t kprop[2] = { cpu_to_be64(KERNEL_LOAD_ADDR), @@ -1717,8 +1661,7 @@ static void spapr_machine_reset(MachineState *machine) { SpaprMachineState *spapr = SPAPR_MACHINE(machine); PowerPCCPU *first_ppc_cpu; - uint32_t rtas_limit; - hwaddr rtas_addr, fdt_addr; + hwaddr fdt_addr; void *fdt; int rc; @@ -1739,16 +1682,6 @@ static void spapr_machine_reset(MachineState *machine) spapr_setup_hpt_and_vrma(spapr); } - /* - * NVLink2-connected GPU RAM needs to be placed on a separate NUMA node. - * We assign a new numa ID per GPU in spapr_pci_collect_nvgpu() which is - * called from vPHB reset handler so we initialize the counter here. - * If no NUMA is configured from the QEMU side, we start from 1 as GPU RAM - * must be equally distant from any other node. - * The final value of spapr->gpu_numa_id is going to be written to - * max-associativity-domains in spapr_build_fdt(). - */ - spapr->gpu_numa_id = MAX(1, machine->numa_state->num_nodes); qemu_devices_reset(); /* @@ -1792,14 +1725,10 @@ static void spapr_machine_reset(MachineState *machine) * or just below 2GB, whichever is lower, so that it can be * processed with 32-bit real mode code if necessary */ - rtas_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR); - rtas_addr = rtas_limit - RTAS_MAX_SIZE; - fdt_addr = rtas_addr - FDT_MAX_SIZE; + fdt_addr = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FDT_MAX_SIZE; fdt = spapr_build_fdt(spapr); - spapr_load_rtas(spapr, fdt, rtas_addr); - rc = fdt_pack(fdt); /* Should only fail if we've built a corrupted tree */ @@ -2847,13 +2776,57 @@ static void spapr_machine_init(MachineState *machine) spapr_ovec_set(spapr->ov5, OV5_DRMEM_V2); /* advertise XIVE on POWER9 machines */ - if (spapr->irq->ov5 & (SPAPR_OV5_XIVE_EXPLOIT | SPAPR_OV5_XIVE_BOTH)) { + if (spapr->irq->xive) { spapr_ovec_set(spapr->ov5, OV5_XIVE_EXPLOIT); } /* init CPUs */ spapr_init_cpus(spapr); + /* + * check we don't have a memory-less/cpu-less NUMA node + * Firmware relies on the existing memory/cpu topology to provide the + * NUMA topology to the kernel. + * And the linux kernel needs to know the NUMA topology at start + * to be able to hotplug CPUs later. + */ + if (machine->numa_state->num_nodes) { + for (i = 0; i < machine->numa_state->num_nodes; ++i) { + /* check for memory-less node */ + if (machine->numa_state->nodes[i].node_mem == 0) { + CPUState *cs; + int found = 0; + /* check for cpu-less node */ + CPU_FOREACH(cs) { + PowerPCCPU *cpu = POWERPC_CPU(cs); + if (cpu->node_id == i) { + found = 1; + break; + } + } + /* memory-less and cpu-less node */ + if (!found) { + error_report( + "Memory-less/cpu-less nodes are not supported (node %d)", + i); + exit(1); + } + } + } + + } + + /* + * NVLink2-connected GPU RAM needs to be placed on a separate NUMA node. + * We assign a new numa ID per GPU in spapr_pci_collect_nvgpu() which is + * called from vPHB reset handler so we initialize the counter here. + * If no NUMA is configured from the QEMU side, we start from 1 as GPU RAM + * must be equally distant from any other node. + * The final value of spapr->gpu_numa_id is going to be written to + * max-associativity-domains in spapr_build_fdt(). + */ + spapr->gpu_numa_id = MAX(1, machine->numa_state->num_nodes); + if ((!kvm_enabled() || kvmppc_has_cap_mmu_radix()) && ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0, spapr->max_compat_pvr)) { @@ -2915,28 +2888,6 @@ static void spapr_machine_init(MachineState *machine) spapr_create_lmb_dr_connectors(spapr); } - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin"); - if (!filename) { - error_report("Could not find LPAR rtas '%s'", "spapr-rtas.bin"); - exit(1); - } - spapr->rtas_size = get_image_size(filename); - if (spapr->rtas_size < 0) { - error_report("Could not get size of LPAR rtas '%s'", filename); - exit(1); - } - spapr->rtas_blob = g_malloc(spapr->rtas_size); - if (load_image_size(filename, spapr->rtas_blob, spapr->rtas_size) < 0) { - error_report("Could not load LPAR rtas '%s'", filename); - exit(1); - } - if (spapr->rtas_size > RTAS_MAX_SIZE) { - error_report("RTAS too big ! 0x%zx bytes (max is 0x%x)", - (size_t)spapr->rtas_size, RTAS_MAX_SIZE); - exit(1); - } - g_free(filename); - /* Set up RTAS event infrastructure */ spapr_events_init(spapr); @@ -4321,6 +4272,8 @@ static void spapr_pic_print_info(InterruptStatsProvider *obj, SpaprMachineState *spapr = SPAPR_MACHINE(obj); spapr->irq->print_info(spapr, mon); + monitor_printf(mon, "irqchip: %s\n", + kvm_irqchip_in_kernel() ? "in-kernel" : "emulated"); } int spapr_get_vcpu_id(PowerPCCPU *cpu) diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 23e4bdb829..140f05c1c6 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1765,8 +1765,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, exit(EXIT_FAILURE); } } - spapr->cas_legacy_guest_workaround = !spapr_ovec_test(ov1_guest, - OV1_PPC_3_00); + spapr->cas_pre_isa3_guest = !spapr_ovec_test(ov1_guest, OV1_PPC_3_00); spapr_ovec_cleanup(ov1_guest); if (!spapr->cas_reboot) { /* If spapr_machine_reset() did not set up a HPT but one is necessary @@ -1785,13 +1784,13 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, * terminate the boot. */ if (guest_xive) { - if (spapr->irq->ov5 == SPAPR_OV5_XIVE_LEGACY) { + if (!spapr->irq->xive) { error_report( "Guest requested unavailable interrupt mode (XIVE), try the ic-mode=xive or ic-mode=dual machine property"); exit(EXIT_FAILURE); } } else { - if (spapr->irq->ov5 == SPAPR_OV5_XIVE_EXPLOIT) { + if (!spapr->irq->xics) { error_report( "Guest requested unavailable interrupt mode (XICS), either don't set the ic-mode machine property or try ic-mode=xics or ic-mode=dual"); exit(EXIT_FAILURE); @@ -1805,7 +1804,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, */ if (!spapr->cas_reboot) { spapr->cas_reboot = spapr_ovec_test(ov5_updates, OV5_XIVE_EXPLOIT) - && spapr->irq->ov5 & SPAPR_OV5_XIVE_BOTH; + && spapr->irq->xics && spapr->irq->xive; } spapr_ovec_cleanup(ov5_updates); diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c index e87b3d50f7..3d3bcc8649 100644 --- a/hw/ppc/spapr_iommu.c +++ b/hw/ppc/spapr_iommu.c @@ -205,9 +205,10 @@ static int spapr_tce_get_attr(IOMMUMemoryRegion *iommu, return -EINVAL; } -static void spapr_tce_notify_flag_changed(IOMMUMemoryRegion *iommu, - IOMMUNotifierFlag old, - IOMMUNotifierFlag new) +static int spapr_tce_notify_flag_changed(IOMMUMemoryRegion *iommu, + IOMMUNotifierFlag old, + IOMMUNotifierFlag new, + Error **errp) { struct SpaprTceTable *tbl = container_of(iommu, SpaprTceTable, iommu); @@ -216,6 +217,7 @@ static void spapr_tce_notify_flag_changed(IOMMUMemoryRegion *iommu, } else if (old != IOMMU_NOTIFIER_NONE && new == IOMMU_NOTIFIER_NONE) { spapr_tce_set_need_vfio(tbl, false); } + return 0; } static int spapr_tce_table_post_load(void *opaque, int version_id) diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c index 06fe2432ba..457eabe24c 100644 --- a/hw/ppc/spapr_irq.c +++ b/hw/ppc/spapr_irq.c @@ -92,44 +92,15 @@ static void spapr_irq_init_kvm(SpaprMachineState *spapr, * XICS IRQ backend. */ -static void spapr_irq_init_xics(SpaprMachineState *spapr, int nr_irqs, - Error **errp) -{ - Object *obj; - Error *local_err = NULL; - - obj = object_new(TYPE_ICS_SIMPLE); - object_property_add_child(OBJECT(spapr), "ics", obj, &error_abort); - object_property_add_const_link(obj, ICS_PROP_XICS, OBJECT(spapr), - &error_fatal); - object_property_set_int(obj, nr_irqs, "nr-irqs", &error_fatal); - object_property_set_bool(obj, true, "realized", &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - spapr->ics = ICS_BASE(obj); - - xics_spapr_init(spapr); -} - -#define ICS_IRQ_FREE(ics, srcno) \ - (!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK))) - static int spapr_irq_claim_xics(SpaprMachineState *spapr, int irq, bool lsi, Error **errp) { ICSState *ics = spapr->ics; assert(ics); + assert(ics_valid_irq(ics, irq)); - if (!ics_valid_irq(ics, irq)) { - error_setg(errp, "IRQ %d is invalid", irq); - return -1; - } - - if (!ICS_IRQ_FREE(ics, irq - ics->offset)) { + if (!ics_irq_free(ics, irq - ics->offset)) { error_setg(errp, "IRQ %d is not free", irq); return -1; } @@ -138,33 +109,14 @@ static int spapr_irq_claim_xics(SpaprMachineState *spapr, int irq, bool lsi, return 0; } -static void spapr_irq_free_xics(SpaprMachineState *spapr, int irq, int num) +static void spapr_irq_free_xics(SpaprMachineState *spapr, int irq) { ICSState *ics = spapr->ics; uint32_t srcno = irq - ics->offset; - int i; - if (ics_valid_irq(ics, irq)) { - trace_spapr_irq_free(0, irq, num); - for (i = srcno; i < srcno + num; ++i) { - if (ICS_IRQ_FREE(ics, i)) { - trace_spapr_irq_free_warn(0, i); - } - memset(&ics->irqs[i], 0, sizeof(ICSIRQState)); - } - } -} + assert(ics_valid_irq(ics, irq)); -static qemu_irq spapr_qirq_xics(SpaprMachineState *spapr, int irq) -{ - ICSState *ics = spapr->ics; - uint32_t srcno = irq - ics->offset; - - if (ics_valid_irq(ics, irq)) { - return spapr->qirqs[srcno]; - } - - return NULL; + memset(&ics->irqs[srcno], 0, sizeof(ICSIRQState)); } static void spapr_irq_print_info_xics(SpaprMachineState *spapr, Monitor *mon) @@ -209,11 +161,12 @@ static int spapr_irq_post_load_xics(SpaprMachineState *spapr, int version_id) return 0; } -static void spapr_irq_set_irq_xics(void *opaque, int srcno, int val) +static void spapr_irq_set_irq_xics(void *opaque, int irq, int val) { SpaprMachineState *spapr = opaque; + uint32_t srcno = irq - spapr->ics->offset; - ics_simple_set_irq(spapr->ics, srcno, val); + ics_set_irq(spapr->ics, srcno, val); } static void spapr_irq_reset_xics(SpaprMachineState *spapr, Error **errp) @@ -227,11 +180,6 @@ static void spapr_irq_reset_xics(SpaprMachineState *spapr, Error **errp) } } -static const char *spapr_irq_get_nodename_xics(SpaprMachineState *spapr) -{ - return XICS_NODENAME; -} - static void spapr_irq_init_kvm_xics(SpaprMachineState *spapr, Error **errp) { if (kvm_enabled()) { @@ -239,88 +187,36 @@ static void spapr_irq_init_kvm_xics(SpaprMachineState *spapr, Error **errp) } } -#define SPAPR_IRQ_XICS_NR_IRQS 0x1000 -#define SPAPR_IRQ_XICS_NR_MSIS \ - (XICS_IRQ_BASE + SPAPR_IRQ_XICS_NR_IRQS - SPAPR_IRQ_MSI) - SpaprIrq spapr_irq_xics = { - .nr_irqs = SPAPR_IRQ_XICS_NR_IRQS, - .nr_msis = SPAPR_IRQ_XICS_NR_MSIS, - .ov5 = SPAPR_OV5_XIVE_LEGACY, + .nr_xirqs = SPAPR_NR_XIRQS, + .nr_msis = SPAPR_NR_MSIS, + .xics = true, + .xive = false, - .init = spapr_irq_init_xics, .claim = spapr_irq_claim_xics, .free = spapr_irq_free_xics, - .qirq = spapr_qirq_xics, .print_info = spapr_irq_print_info_xics, .dt_populate = spapr_dt_xics, .cpu_intc_create = spapr_irq_cpu_intc_create_xics, .post_load = spapr_irq_post_load_xics, .reset = spapr_irq_reset_xics, .set_irq = spapr_irq_set_irq_xics, - .get_nodename = spapr_irq_get_nodename_xics, .init_kvm = spapr_irq_init_kvm_xics, }; /* * XIVE IRQ backend. */ -static void spapr_irq_init_xive(SpaprMachineState *spapr, int nr_irqs, - Error **errp) -{ - uint32_t nr_servers = spapr_max_server_number(spapr); - DeviceState *dev; - int i; - - dev = qdev_create(NULL, TYPE_SPAPR_XIVE); - qdev_prop_set_uint32(dev, "nr-irqs", nr_irqs); - /* - * 8 XIVE END structures per CPU. One for each available priority - */ - qdev_prop_set_uint32(dev, "nr-ends", nr_servers << 3); - qdev_init_nofail(dev); - - spapr->xive = SPAPR_XIVE(dev); - - /* Enable the CPU IPIs */ - for (i = 0; i < nr_servers; ++i) { - spapr_xive_irq_claim(spapr->xive, SPAPR_IRQ_IPI + i, false); - } - - spapr_xive_hcall_init(spapr); -} static int spapr_irq_claim_xive(SpaprMachineState *spapr, int irq, bool lsi, Error **errp) { - if (!spapr_xive_irq_claim(spapr->xive, irq, lsi)) { - error_setg(errp, "IRQ %d is invalid", irq); - return -1; - } - return 0; + return spapr_xive_irq_claim(spapr->xive, irq, lsi, errp); } -static void spapr_irq_free_xive(SpaprMachineState *spapr, int irq, int num) +static void spapr_irq_free_xive(SpaprMachineState *spapr, int irq) { - int i; - - for (i = irq; i < irq + num; ++i) { - spapr_xive_irq_free(spapr->xive, i); - } -} - -static qemu_irq spapr_qirq_xive(SpaprMachineState *spapr, int irq) -{ - SpaprXive *xive = spapr->xive; - - if (irq >= xive->nr_irqs) { - return NULL; - } - - /* The sPAPR machine/device should have claimed the IRQ before */ - assert(xive_eas_is_valid(&xive->eat[irq])); - - return spapr->qirqs[irq]; + spapr_xive_irq_free(spapr->xive, irq); } static void spapr_irq_print_info_xive(SpaprMachineState *spapr, @@ -386,22 +282,17 @@ static void spapr_irq_reset_xive(SpaprMachineState *spapr, Error **errp) spapr_xive_mmio_set_enabled(spapr->xive, true); } -static void spapr_irq_set_irq_xive(void *opaque, int srcno, int val) +static void spapr_irq_set_irq_xive(void *opaque, int irq, int val) { SpaprMachineState *spapr = opaque; if (kvm_irqchip_in_kernel()) { - kvmppc_xive_source_set_irq(&spapr->xive->source, srcno, val); + kvmppc_xive_source_set_irq(&spapr->xive->source, irq, val); } else { - xive_source_set_irq(&spapr->xive->source, srcno, val); + xive_source_set_irq(&spapr->xive->source, irq, val); } } -static const char *spapr_irq_get_nodename_xive(SpaprMachineState *spapr) -{ - return spapr->xive->nodename; -} - static void spapr_irq_init_kvm_xive(SpaprMachineState *spapr, Error **errp) { if (kvm_enabled()) { @@ -409,30 +300,20 @@ static void spapr_irq_init_kvm_xive(SpaprMachineState *spapr, Error **errp) } } -/* - * XIVE uses the full IRQ number space. Set it to 8K to be compatible - * with XICS. - */ - -#define SPAPR_IRQ_XIVE_NR_IRQS 0x2000 -#define SPAPR_IRQ_XIVE_NR_MSIS (SPAPR_IRQ_XIVE_NR_IRQS - SPAPR_IRQ_MSI) - SpaprIrq spapr_irq_xive = { - .nr_irqs = SPAPR_IRQ_XIVE_NR_IRQS, - .nr_msis = SPAPR_IRQ_XIVE_NR_MSIS, - .ov5 = SPAPR_OV5_XIVE_EXPLOIT, + .nr_xirqs = SPAPR_NR_XIRQS, + .nr_msis = SPAPR_NR_MSIS, + .xics = false, + .xive = true, - .init = spapr_irq_init_xive, .claim = spapr_irq_claim_xive, .free = spapr_irq_free_xive, - .qirq = spapr_qirq_xive, .print_info = spapr_irq_print_info_xive, .dt_populate = spapr_dt_xive, .cpu_intc_create = spapr_irq_cpu_intc_create_xive, .post_load = spapr_irq_post_load_xive, .reset = spapr_irq_reset_xive, .set_irq = spapr_irq_set_irq_xive, - .get_nodename = spapr_irq_get_nodename_xive, .init_kvm = spapr_irq_init_kvm_xive, }; @@ -455,24 +336,6 @@ static SpaprIrq *spapr_irq_current(SpaprMachineState *spapr) &spapr_irq_xive : &spapr_irq_xics; } -static void spapr_irq_init_dual(SpaprMachineState *spapr, int nr_irqs, - Error **errp) -{ - Error *local_err = NULL; - - spapr_irq_xics.init(spapr, spapr_irq_xics.nr_irqs, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - spapr_irq_xive.init(spapr, spapr_irq_xive.nr_irqs, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } -} - static int spapr_irq_claim_dual(SpaprMachineState *spapr, int irq, bool lsi, Error **errp) { @@ -494,15 +357,10 @@ static int spapr_irq_claim_dual(SpaprMachineState *spapr, int irq, bool lsi, return ret; } -static void spapr_irq_free_dual(SpaprMachineState *spapr, int irq, int num) +static void spapr_irq_free_dual(SpaprMachineState *spapr, int irq) { - spapr_irq_xics.free(spapr, irq, num); - spapr_irq_xive.free(spapr, irq, num); -} - -static qemu_irq spapr_qirq_dual(SpaprMachineState *spapr, int irq) -{ - return spapr_irq_current(spapr)->qirq(spapr, irq); + spapr_irq_xics.free(spapr, irq); + spapr_irq_xive.free(spapr, irq); } static void spapr_irq_print_info_dual(SpaprMachineState *spapr, Monitor *mon) @@ -576,45 +434,35 @@ static void spapr_irq_reset_dual(SpaprMachineState *spapr, Error **errp) spapr_irq_current(spapr)->reset(spapr, errp); } -static void spapr_irq_set_irq_dual(void *opaque, int srcno, int val) +static void spapr_irq_set_irq_dual(void *opaque, int irq, int val) { SpaprMachineState *spapr = opaque; - spapr_irq_current(spapr)->set_irq(spapr, srcno, val); -} - -static const char *spapr_irq_get_nodename_dual(SpaprMachineState *spapr) -{ - return spapr_irq_current(spapr)->get_nodename(spapr); + spapr_irq_current(spapr)->set_irq(spapr, irq, val); } /* * Define values in sync with the XIVE and XICS backend */ -#define SPAPR_IRQ_DUAL_NR_IRQS 0x2000 -#define SPAPR_IRQ_DUAL_NR_MSIS (SPAPR_IRQ_DUAL_NR_IRQS - SPAPR_IRQ_MSI) - SpaprIrq spapr_irq_dual = { - .nr_irqs = SPAPR_IRQ_DUAL_NR_IRQS, - .nr_msis = SPAPR_IRQ_DUAL_NR_MSIS, - .ov5 = SPAPR_OV5_XIVE_BOTH, + .nr_xirqs = SPAPR_NR_XIRQS, + .nr_msis = SPAPR_NR_MSIS, + .xics = true, + .xive = true, - .init = spapr_irq_init_dual, .claim = spapr_irq_claim_dual, .free = spapr_irq_free_dual, - .qirq = spapr_qirq_dual, .print_info = spapr_irq_print_info_dual, .dt_populate = spapr_irq_dt_populate_dual, .cpu_intc_create = spapr_irq_cpu_intc_create_dual, .post_load = spapr_irq_post_load_dual, .reset = spapr_irq_reset_dual, .set_irq = spapr_irq_set_irq_dual, - .get_nodename = spapr_irq_get_nodename_dual, .init_kvm = NULL, /* should not be used */ }; -static void spapr_irq_check(SpaprMachineState *spapr, Error **errp) +static int spapr_irq_check(SpaprMachineState *spapr, Error **errp) { MachineState *machine = MACHINE(spapr); @@ -630,7 +478,7 @@ static void spapr_irq_check(SpaprMachineState *spapr, Error **errp) */ if (spapr->irq == &spapr_irq_dual) { spapr->irq = &spapr_irq_xics; - return; + return 0; } /* @@ -650,7 +498,7 @@ static void spapr_irq_check(SpaprMachineState *spapr, Error **errp) */ if (spapr->irq == &spapr_irq_xive) { error_setg(errp, "XIVE-only machines require a POWER9 CPU"); - return; + return -1; } } @@ -664,8 +512,10 @@ static void spapr_irq_check(SpaprMachineState *spapr, Error **errp) machine_kernel_irqchip_required(machine) && xics_kvm_has_broken_disconnect(spapr)) { error_setg(errp, "KVM is too old to support ic-mode=dual,kernel-irqchip=on"); - return; + return -1; } + + return 0; } /* @@ -674,7 +524,6 @@ static void spapr_irq_check(SpaprMachineState *spapr, Error **errp) void spapr_irq_init(SpaprMachineState *spapr, Error **errp) { MachineState *machine = MACHINE(spapr); - Error *local_err = NULL; if (machine_kernel_irqchip_split(machine)) { error_setg(errp, "kernel_irqchip split mode not supported on pseries"); @@ -687,9 +536,7 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) return; } - spapr_irq_check(spapr, &local_err); - if (local_err) { - error_propagate(errp, local_err); + if (spapr_irq_check(spapr, errp) < 0) { return; } @@ -698,25 +545,113 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp) spapr_irq_msi_init(spapr, spapr->irq->nr_msis); } - spapr->irq->init(spapr, spapr->irq->nr_irqs, errp); + if (spapr->irq->xics) { + Error *local_err = NULL; + Object *obj; + + obj = object_new(TYPE_ICS_SPAPR); + object_property_add_child(OBJECT(spapr), "ics", obj, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + object_property_add_const_link(obj, ICS_PROP_XICS, OBJECT(spapr), + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + object_property_set_int(obj, spapr->irq->nr_xirqs, "nr-irqs", + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + object_property_set_bool(obj, true, "realized", &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + spapr->ics = ICS_SPAPR(obj); + } + + if (spapr->irq->xive) { + uint32_t nr_servers = spapr_max_server_number(spapr); + DeviceState *dev; + int i; + + dev = qdev_create(NULL, TYPE_SPAPR_XIVE); + qdev_prop_set_uint32(dev, "nr-irqs", + spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE); + /* + * 8 XIVE END structures per CPU. One for each available + * priority + */ + qdev_prop_set_uint32(dev, "nr-ends", nr_servers << 3); + qdev_init_nofail(dev); + + spapr->xive = SPAPR_XIVE(dev); + + /* Enable the CPU IPIs */ + for (i = 0; i < nr_servers; ++i) { + if (spapr_xive_irq_claim(spapr->xive, SPAPR_IRQ_IPI + i, + false, errp) < 0) { + return; + } + } + + spapr_xive_hcall_init(spapr); + } spapr->qirqs = qemu_allocate_irqs(spapr->irq->set_irq, spapr, - spapr->irq->nr_irqs); + spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE); } int spapr_irq_claim(SpaprMachineState *spapr, int irq, bool lsi, Error **errp) { + assert(irq >= SPAPR_XIRQ_BASE); + assert(irq < (spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE)); + return spapr->irq->claim(spapr, irq, lsi, errp); } void spapr_irq_free(SpaprMachineState *spapr, int irq, int num) { - spapr->irq->free(spapr, irq, num); + int i; + + assert(irq >= SPAPR_XIRQ_BASE); + assert((irq + num) <= (spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE)); + + for (i = irq; i < (irq + num); i++) { + spapr->irq->free(spapr, i); + } } qemu_irq spapr_qirq(SpaprMachineState *spapr, int irq) { - return spapr->irq->qirq(spapr, irq); + /* + * This interface is basically for VIO and PHB devices to find the + * right qemu_irq to manipulate, so we only allow access to the + * external irqs for now. Currently anything which needs to + * access the IPIs most naturally gets there via the guest side + * interfaces, we can change this if we need to in future. + */ + assert(irq >= SPAPR_XIRQ_BASE); + assert(irq < (spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE)); + + if (spapr->ics) { + assert(ics_valid_irq(spapr->ics, irq)); + } + if (spapr->xive) { + assert(irq < spapr->xive->nr_irqs); + assert(xive_eas_is_valid(&spapr->xive->eat[irq])); + } + + return spapr->qirqs[irq]; } int spapr_irq_post_load(SpaprMachineState *spapr, int version_id) @@ -735,13 +670,13 @@ void spapr_irq_reset(SpaprMachineState *spapr, Error **errp) int spapr_irq_get_phandle(SpaprMachineState *spapr, void *fdt, Error **errp) { - const char *nodename = spapr->irq->get_nodename(spapr); + const char *nodename = "interrupt-controller"; int offset, phandle; offset = fdt_subnode_offset(fdt, 0, nodename); if (offset < 0) { - error_setg(errp, "Can't find node \"%s\": %s", nodename, - fdt_strerror(offset)); + error_setg(errp, "Can't find node \"%s\": %s", + nodename, fdt_strerror(offset)); return -1; } @@ -767,7 +702,7 @@ static int ics_find_free_block(ICSState *ics, int num, int alignnum) return -1; } for (i = first; i < first + num; ++i) { - if (!ICS_IRQ_FREE(ics, i)) { + if (!ics_irq_free(ics, i)) { break; } } @@ -809,23 +744,21 @@ int spapr_irq_find(SpaprMachineState *spapr, int num, bool align, Error **errp) return first + ics->offset; } -#define SPAPR_IRQ_XICS_LEGACY_NR_IRQS 0x400 +#define SPAPR_IRQ_XICS_LEGACY_NR_XIRQS 0x400 SpaprIrq spapr_irq_xics_legacy = { - .nr_irqs = SPAPR_IRQ_XICS_LEGACY_NR_IRQS, - .nr_msis = SPAPR_IRQ_XICS_LEGACY_NR_IRQS, - .ov5 = SPAPR_OV5_XIVE_LEGACY, + .nr_xirqs = SPAPR_IRQ_XICS_LEGACY_NR_XIRQS, + .nr_msis = SPAPR_IRQ_XICS_LEGACY_NR_XIRQS, + .xics = true, + .xive = false, - .init = spapr_irq_init_xics, .claim = spapr_irq_claim_xics, .free = spapr_irq_free_xics, - .qirq = spapr_qirq_xics, .print_info = spapr_irq_print_info_xics, .dt_populate = spapr_dt_xics, .cpu_intc_create = spapr_irq_cpu_intc_create_xics, .post_load = spapr_irq_post_load_xics, .reset = spapr_irq_reset_xics, .set_irq = spapr_irq_set_irq_xics, - .get_nodename = spapr_irq_get_nodename_xics, .init_kvm = spapr_irq_init_kvm_xics, }; diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 7b71ad7c74..01ff41d4c4 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -721,9 +721,10 @@ static void pci_spapr_set_irq(void *opaque, int irq_num, int level) * corresponding qemu_irq. */ SpaprPhbState *phb = opaque; + SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); trace_spapr_pci_lsi_set(phb->dtbusname, irq_num, phb->lsi_table[irq_num].irq); - qemu_set_irq(spapr_phb_lsi_qirq(phb, irq_num), level); + qemu_set_irq(spapr_qirq(spapr, phb->lsi_table[irq_num].irq), level); } static PCIINTxRoute spapr_route_intx_pin_to_irq(void *opaque, int pin) @@ -835,7 +836,7 @@ static char *spapr_phb_get_loc_code(SpaprPhbState *sphb, PCIDevice *pdev) #define b_fff(x) b_x((x), 8, 3) /* function number */ #define b_rrrrrrrr(x) b_x((x), 0, 8) /* register number */ -/* for 'reg'/'assigned-addresses' OF properties */ +/* for 'reg' OF properties */ #define RESOURCE_CELLS_SIZE 2 #define RESOURCE_CELLS_ADDRESS 3 @@ -849,17 +850,14 @@ typedef struct ResourceFields { typedef struct ResourceProps { ResourceFields reg[8]; - ResourceFields assigned[7]; uint32_t reg_len; - uint32_t assigned_len; } ResourceProps; -/* fill in the 'reg'/'assigned-resources' OF properties for +/* fill in the 'reg' OF properties for * a PCI device. 'reg' describes resource requirements for a - * device's IO/MEM regions, 'assigned-addresses' describes the - * actual resource assignments. + * device's IO/MEM regions. * - * the properties are arrays of ('phys-addr', 'size') pairs describing + * the property is an array of ('phys-addr', 'size') pairs describing * the addressable regions of the PCI device, where 'phys-addr' is a * RESOURCE_CELLS_ADDRESS-tuple of 32-bit integers corresponding to * (phys.hi, phys.mid, phys.lo), and 'size' is a @@ -888,18 +886,7 @@ typedef struct ResourceProps { * phys.mid and phys.lo correspond respectively to the hi/lo portions * of the actual address of the region. * - * how the phys-addr/size values are used differ slightly between - * 'reg' and 'assigned-addresses' properties. namely, 'reg' has - * an additional description for the config space region of the - * device, and in the case of QEMU has n=0 and phys.mid=phys.lo=0 - * to describe the region as relocatable, with an address-mapping - * that corresponds directly to the PHB's address space for the - * resource. 'assigned-addresses' always has n=1 set with an absolute - * address assigned for the resource. in general, 'assigned-addresses' - * won't be populated, since addresses for PCI devices are generally - * unmapped initially and left to the guest to assign. - * - * note also that addresses defined in these properties are, at least + * note also that addresses defined in this property are, at least * for PAPR guests, relative to the PHBs IO/MEM windows, and * correspond directly to the addresses in the BARs. * @@ -913,8 +900,8 @@ static void populate_resource_props(PCIDevice *d, ResourceProps *rp) uint32_t dev_id = (b_bbbbbbbb(bus_num) | b_ddddd(PCI_SLOT(d->devfn)) | b_fff(PCI_FUNC(d->devfn))); - ResourceFields *reg, *assigned; - int i, reg_idx = 0, assigned_idx = 0; + ResourceFields *reg; + int i, reg_idx = 0; /* config space region */ reg = &rp->reg[reg_idx++]; @@ -943,21 +930,9 @@ static void populate_resource_props(PCIDevice *d, ResourceProps *rp) reg->phys_lo = 0; reg->size_hi = cpu_to_be32(d->io_regions[i].size >> 32); reg->size_lo = cpu_to_be32(d->io_regions[i].size); - - if (d->io_regions[i].addr == PCI_BAR_UNMAPPED) { - continue; - } - - assigned = &rp->assigned[assigned_idx++]; - assigned->phys_hi = cpu_to_be32(be32_to_cpu(reg->phys_hi) | b_n(1)); - assigned->phys_mid = cpu_to_be32(d->io_regions[i].addr >> 32); - assigned->phys_lo = cpu_to_be32(d->io_regions[i].addr); - assigned->size_hi = reg->size_hi; - assigned->size_lo = reg->size_lo; } rp->reg_len = reg_idx * sizeof(ResourceFields); - rp->assigned_len = assigned_idx * sizeof(ResourceFields); } typedef struct PCIClass PCIClass; @@ -1471,8 +1446,6 @@ static int spapr_dt_pci_device(SpaprPhbState *sphb, PCIDevice *dev, populate_resource_props(dev, &rp); _FDT(fdt_setprop(fdt, offset, "reg", (uint8_t *)rp.reg, rp.reg_len)); - _FDT(fdt_setprop(fdt, offset, "assigned-addresses", - (uint8_t *)rp.assigned, rp.assigned_len)); if (sphb->pcie_ecs && pci_is_express(dev)) { _FDT(fdt_setprop_cell(fdt, offset, "ibm,pci-config-space-type", 0x1)); diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index bee3835214..8d8d8cdfcb 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -477,47 +477,6 @@ void spapr_dt_rtas_tokens(void *fdt, int rtas) } } -void spapr_load_rtas(SpaprMachineState *spapr, void *fdt, hwaddr addr) -{ - int rtas_node; - int ret; - - /* Copy RTAS blob into guest RAM */ - cpu_physical_memory_write(addr, spapr->rtas_blob, spapr->rtas_size); - - ret = fdt_add_mem_rsv(fdt, addr, spapr->rtas_size); - if (ret < 0) { - error_report("Couldn't add RTAS reserve entry: %s", - fdt_strerror(ret)); - exit(1); - } - - /* Update the device tree with the blob's location */ - rtas_node = fdt_path_offset(fdt, "/rtas"); - assert(rtas_node >= 0); - - ret = fdt_setprop_cell(fdt, rtas_node, "linux,rtas-base", addr); - if (ret < 0) { - error_report("Couldn't add linux,rtas-base property: %s", - fdt_strerror(ret)); - exit(1); - } - - ret = fdt_setprop_cell(fdt, rtas_node, "linux,rtas-entry", addr); - if (ret < 0) { - error_report("Couldn't add linux,rtas-entry property: %s", - fdt_strerror(ret)); - exit(1); - } - - ret = fdt_setprop_cell(fdt, rtas_node, "rtas-size", spapr->rtas_size); - if (ret < 0) { - error_report("Couldn't add rtas-size property: %s", - fdt_strerror(ret)); - exit(1); - } -} - static void core_rtas_register_types(void) { spapr_rtas_register(RTAS_DISPLAY_CHARACTER, "display-character", diff --git a/hw/ppc/spapr_tpm_proxy.c b/hw/ppc/spapr_tpm_proxy.c index b835d25be6..ca1caec113 100644 --- a/hw/ppc/spapr_tpm_proxy.c +++ b/hw/ppc/spapr_tpm_proxy.c @@ -114,7 +114,7 @@ static target_ulong h_tpm_comm(PowerPCCPU *cpu, return H_FUNCTION; } - trace_spapr_h_tpm_comm(tpm_proxy->host_path ?: "null", op); + trace_spapr_h_tpm_comm(tpm_proxy->host_path, op); switch (op) { case TPM_COMM_OP_EXECUTE: diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index 0803649658..554de9930d 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -23,7 +23,6 @@ #include "qemu/error-report.h" #include "qapi/error.h" #include "qapi/visitor.h" -#include "hw/irq.h" #include "qemu/log.h" #include "hw/loader.h" #include "elf.h" @@ -294,7 +293,7 @@ int spapr_vio_send_crq(SpaprVioDevice *dev, uint8_t *crq) dev->crq.qnext = (dev->crq.qnext + 16) % dev->crq.qsize; if (dev->signal_state & 1) { - qemu_irq_pulse(spapr_vio_qirq(dev)); + spapr_vio_irq_pulse(dev); } return 0; diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events index 96dad767a1..9ea620f23c 100644 --- a/hw/ppc/trace-events +++ b/hw/ppc/trace-events @@ -13,10 +13,6 @@ spapr_pci_msi_retry(unsigned config_addr, unsigned req_num, unsigned max_irqs) " spapr_cas_failed(unsigned long n) "DT diff buffer is too small: %ld bytes" spapr_cas_continue(unsigned long n) "Copy changes to the guest: %ld bytes" -# spapr_irq.c -spapr_irq_free(int src, int irq, int num) "Source#%d, first irq %d, %d irqs" -spapr_irq_free_warn(int src, int irq) "Source#%d, irq %d is already free" - # spapr_hcall.c spapr_cas_pvr(uint32_t cur_pvr, bool explicit_match, uint32_t new_pvr) "current=0x%x, explicit_match=%u, new=0x%x" spapr_h_resize_hpt_prepare(uint64_t flags, uint64_t shift) "flags=0x%"PRIx64", shift=%"PRIu64 diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index 797ecbb7a9..66205697ae 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -377,9 +377,6 @@ static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code) case SCLP_CMD_WRITE_EVENT_MASK: write_event_mask(ef, sccb); break; - default: - sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); - break; } } diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index 963a41c7f5..2d2f4a7c41 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -695,10 +695,15 @@ static const MemoryRegionOps s390_msi_ctrl_ops = { void s390_pci_iommu_enable(S390PCIIOMMU *iommu) { + /* + * The iommu region is initialized against a 0-mapped address space, + * so the smallest IOMMU region we can define runs from 0 to the end + * of the PCI address space. + */ char *name = g_strdup_printf("iommu-s390-%04x", iommu->pbdev->uid); memory_region_init_iommu(&iommu->iommu_mr, sizeof(iommu->iommu_mr), TYPE_S390_IOMMU_MEMORY_REGION, OBJECT(&iommu->mr), - name, iommu->pal - iommu->pba + 1); + name, iommu->pal + 1); iommu->enabled = true; memory_region_add_subregion(&iommu->mr, 0, MEMORY_REGION(&iommu->iommu_mr)); g_free(name); diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 8bfb6684cb..18ad279a00 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -154,39 +154,15 @@ static void virtio_ccw_register_hcalls(void) virtio_ccw_hcall_early_printk); } -/* - * KVM does only support memory slots up to KVM_MEM_MAX_NR_PAGES pages - * as the dirty bitmap must be managed by bitops that take an int as - * position indicator. If we have a guest beyond that we will split off - * new subregions. The split must happen on a segment boundary (1MB). - */ -#define KVM_MEM_MAX_NR_PAGES ((1ULL << 31) - 1) -#define SEG_MSK (~0xfffffULL) -#define KVM_SLOT_MAX_BYTES ((KVM_MEM_MAX_NR_PAGES * TARGET_PAGE_SIZE) & SEG_MSK) static void s390_memory_init(ram_addr_t mem_size) { MemoryRegion *sysmem = get_system_memory(); - ram_addr_t chunk, offset = 0; - unsigned int number = 0; + MemoryRegion *ram = g_new(MemoryRegion, 1); Error *local_err = NULL; - gchar *name; /* allocate RAM for core */ - name = g_strdup_printf("s390.ram"); - while (mem_size) { - MemoryRegion *ram = g_new(MemoryRegion, 1); - uint64_t size = mem_size; - - /* KVM does not allow memslots >= 8 TB */ - chunk = MIN(size, KVM_SLOT_MAX_BYTES); - memory_region_allocate_system_memory(ram, NULL, name, chunk); - memory_region_add_subregion(sysmem, offset, ram); - mem_size -= chunk; - offset += chunk; - g_free(name); - name = g_strdup_printf("s390.ram.%u", ++number); - } - g_free(name); + memory_region_allocate_system_memory(ram, NULL, "s390.ram", mem_size); + memory_region_add_subregion(sysmem, 0, ram); /* * Configure the maximum page size. As no memory devices were created diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index fac7c3bb6c..f57ce7b739 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -68,6 +68,12 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb) read_info->ibc_val = cpu_to_be32(s390_get_ibc_val()); + if (be16_to_cpu(sccb->h.length) < + (sizeof(ReadInfo) + cpu_count * sizeof(CPUEntry))) { + sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH); + return; + } + /* Configuration Characteristic (Extension) */ s390_get_feat_block(S390_FEAT_TYPE_SCLP_CONF_CHAR, read_info->conf_char); @@ -118,6 +124,12 @@ static void sclp_read_cpu_info(SCLPDevice *sclp, SCCB *sccb) cpu_info->offset_configured = cpu_to_be16(offsetof(ReadCpuInfo, entries)); cpu_info->nr_standby = cpu_to_be16(0); + if (be16_to_cpu(sccb->h.length) < + (sizeof(ReadCpuInfo) + cpu_count * sizeof(CPUEntry))) { + sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH); + return; + } + /* The standby offset is 16-byte for each CPU */ cpu_info->offset_standby = cpu_to_be16(cpu_info->offset_configured + cpu_info->nr_configured*sizeof(CPUEntry)); @@ -213,14 +225,33 @@ int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code) cpu_physical_memory_read(sccb, &work_sccb, sccb_len); /* Valid sccb sizes */ - if (be16_to_cpu(work_sccb.h.length) < sizeof(SCCBHeader) || - be16_to_cpu(work_sccb.h.length) > SCCB_SIZE) { + if (be16_to_cpu(work_sccb.h.length) < sizeof(SCCBHeader)) { r = -PGM_SPECIFICATION; goto out; } - sclp_c->execute(sclp, &work_sccb, code); + switch (code & SCLP_CMD_CODE_MASK) { + case SCLP_CMDW_READ_SCP_INFO: + case SCLP_CMDW_READ_SCP_INFO_FORCED: + case SCLP_CMDW_READ_CPU_INFO: + case SCLP_CMDW_CONFIGURE_IOA: + case SCLP_CMDW_DECONFIGURE_IOA: + case SCLP_CMD_READ_EVENT_DATA: + case SCLP_CMD_WRITE_EVENT_DATA: + case SCLP_CMD_WRITE_EVENT_MASK: + break; + default: + work_sccb.h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); + goto out_write; + } + + if ((sccb + be16_to_cpu(work_sccb.h.length)) > ((sccb & PAGE_MASK) + PAGE_SIZE)) { + work_sccb.h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION); + goto out_write; + } + sclp_c->execute(sclp, &work_sccb, code); +out_write: cpu_physical_memory_write(sccb, &work_sccb, be16_to_cpu(work_sccb.h.length)); diff --git a/hw/timer/lm32_timer.c b/hw/timer/lm32_timer.c index ac3edaff4f..cf316edb7f 100644 --- a/hw/timer/lm32_timer.c +++ b/hw/timer/lm32_timer.c @@ -186,9 +186,6 @@ static void lm32_timer_init(Object *obj) sysbus_init_irq(dev, &s->irq); - s->bh = qemu_bh_new(timer_hit, s); - s->ptimer = ptimer_init(s->bh, PTIMER_POLICY_DEFAULT); - memory_region_init_io(&s->iomem, obj, &timer_ops, s, "timer", R_MAX * 4); sysbus_init_mmio(dev, &s->iomem); @@ -198,6 +195,9 @@ static void lm32_timer_realize(DeviceState *dev, Error **errp) { LM32TimerState *s = LM32_TIMER(dev); + s->bh = qemu_bh_new(timer_hit, s); + s->ptimer = ptimer_init(s->bh, PTIMER_POLICY_DEFAULT); + ptimer_set_freq(s->ptimer, s->freq_hz); } diff --git a/hw/timer/milkymist-sysctl.c b/hw/timer/milkymist-sysctl.c index 958350767a..6aedc11bef 100644 --- a/hw/timer/milkymist-sysctl.c +++ b/hw/timer/milkymist-sysctl.c @@ -283,11 +283,6 @@ static void milkymist_sysctl_init(Object *obj) sysbus_init_irq(dev, &s->timer0_irq); sysbus_init_irq(dev, &s->timer1_irq); - s->bh0 = qemu_bh_new(timer0_hit, s); - s->bh1 = qemu_bh_new(timer1_hit, s); - s->ptimer0 = ptimer_init(s->bh0, PTIMER_POLICY_DEFAULT); - s->ptimer1 = ptimer_init(s->bh1, PTIMER_POLICY_DEFAULT); - memory_region_init_io(&s->regs_region, obj, &sysctl_mmio_ops, s, "milkymist-sysctl", R_MAX * 4); sysbus_init_mmio(dev, &s->regs_region); @@ -297,6 +292,11 @@ static void milkymist_sysctl_realize(DeviceState *dev, Error **errp) { MilkymistSysctlState *s = MILKYMIST_SYSCTL(dev); + s->bh0 = qemu_bh_new(timer0_hit, s); + s->bh1 = qemu_bh_new(timer1_hit, s); + s->ptimer0 = ptimer_init(s->bh0, PTIMER_POLICY_DEFAULT); + s->ptimer1 = ptimer_init(s->bh1, PTIMER_POLICY_DEFAULT); + ptimer_set_freq(s->ptimer0, s->freq_hz); ptimer_set_freq(s->ptimer1, s->freq_hz); } diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 3e03c495d8..5ca11488d6 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -509,6 +509,7 @@ static void vfio_listener_region_add(MemoryListener *listener, int ret; VFIOHostDMAWindow *hostwin; bool hostwin_found; + Error *err = NULL; if (vfio_listener_skipped_section(section)) { trace_vfio_listener_region_add_skip( @@ -543,13 +544,20 @@ static void vfio_listener_region_add(MemoryListener *listener, hostwin->max_iova - hostwin->min_iova + 1, section->offset_within_address_space, int128_get64(section->size))) { - ret = -1; + error_setg(&err, + "region [0x%"PRIx64",0x%"PRIx64"] overlaps with existing" + "host DMA window [0x%"PRIx64",0x%"PRIx64"]", + section->offset_within_address_space, + section->offset_within_address_space + + int128_get64(section->size) - 1, + hostwin->min_iova, hostwin->max_iova); goto fail; } } ret = vfio_spapr_create_window(container, section, &pgsize); if (ret) { + error_setg_errno(&err, -ret, "Failed to create SPAPR window"); goto fail; } @@ -594,10 +602,8 @@ static void vfio_listener_region_add(MemoryListener *listener, } if (!hostwin_found) { - error_report("vfio: IOMMU container %p can't map guest IOVA region" - " 0x%"HWADDR_PRIx"..0x%"HWADDR_PRIx, - container, iova, end); - ret = -EFAULT; + error_setg(&err, "Container %p can't map guest IOVA region" + " 0x%"HWADDR_PRIx"..0x%"HWADDR_PRIx, container, iova, end); goto fail; } @@ -630,9 +636,14 @@ static void vfio_listener_region_add(MemoryListener *listener, section->offset_within_region, int128_get64(llend), iommu_idx); - QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next); - memory_region_register_iommu_notifier(section->mr, &giommu->n); + ret = memory_region_register_iommu_notifier(section->mr, &giommu->n, + &err); + if (ret) { + g_free(giommu); + goto fail; + } + QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next); memory_region_iommu_replay(giommu->iommu, &giommu->n); return; @@ -664,11 +675,12 @@ static void vfio_listener_region_add(MemoryListener *listener, ret = vfio_dma_map(container, iova, int128_get64(llsize), vaddr, section->readonly); if (ret) { - error_report("vfio_dma_map(%p, 0x%"HWADDR_PRIx", " - "0x%"HWADDR_PRIx", %p) = %d (%m)", - container, iova, int128_get64(llsize), vaddr, ret); + error_setg(&err, "vfio_dma_map(%p, 0x%"HWADDR_PRIx", " + "0x%"HWADDR_PRIx", %p) = %d (%m)", + container, iova, int128_get64(llsize), vaddr, ret); if (memory_region_is_ram_device(section->mr)) { /* Allow unexpected mappings not to be fatal for RAM devices */ + error_report_err(err); return; } goto fail; @@ -688,9 +700,14 @@ fail: */ if (!container->initialized) { if (!container->error) { - container->error = ret; + error_propagate_prepend(&container->error, err, + "Region %s: ", + memory_region_name(section->mr)); + } else { + error_free(err); } } else { + error_report_err(err); hw_error("vfio: DMA mapping failed, unable to continue"); } } @@ -1251,6 +1268,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, container = g_malloc0(sizeof(*container)); container->space = space; container->fd = fd; + container->error = NULL; QLIST_INIT(&container->giommu_list); QLIST_INIT(&container->hostwin_list); @@ -1308,9 +1326,9 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, &address_space_memory); if (container->error) { memory_listener_unregister(&container->prereg_listener); - ret = container->error; - error_setg(errp, - "RAM memory listener initialization failed for container"); + ret = -1; + error_propagate_prepend(errp, container->error, + "RAM memory listener initialization failed: "); goto free_container_exit; } } @@ -1365,9 +1383,9 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, memory_listener_register(&container->listener, container->space->as); if (container->error) { - ret = container->error; - error_setg_errno(errp, -ret, - "memory listener initialization failed for container"); + ret = -1; + error_propagate_prepend(errp, container->error, + "memory listener initialization failed: "); goto listener_release_exit; } diff --git a/hw/vfio/spapr.c b/hw/vfio/spapr.c index 96c0ad9d9b..e853eebe11 100644 --- a/hw/vfio/spapr.c +++ b/hw/vfio/spapr.c @@ -17,6 +17,7 @@ #include "hw/hw.h" #include "exec/ram_addr.h" #include "qemu/error-report.h" +#include "qapi/error.h" #include "trace.h" static bool vfio_prereg_listener_skipped_section(MemoryRegionSection *section) @@ -85,7 +86,8 @@ static void vfio_prereg_listener_region_add(MemoryListener *listener, */ if (!container->initialized) { if (!container->error) { - container->error = ret; + error_setg_errno(&container->error, -ret, + "Memory registering failed"); } } else { hw_error("vfio: Memory registering failed, unable to continue"); diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 34accdf615..99de5f196f 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -451,8 +451,13 @@ static void vhost_commit(MemoryListener *listener) changed = true; } else { /* Same size, lets check the contents */ - changed = n_old_sections && memcmp(dev->mem_sections, old_sections, - n_old_sections * sizeof(old_sections[0])) != 0; + for (int i = 0; i < n_old_sections; i++) { + if (!MemoryRegionSection_eq(&old_sections[i], + &dev->mem_sections[i])) { + changed = true; + break; + } + } } trace_vhost_commit(dev->started, changed); @@ -672,8 +677,9 @@ static void vhost_iommu_region_add(MemoryListener *listener, iommu_listener); struct vhost_iommu *iommu; Int128 end; - int iommu_idx; + int iommu_idx, ret; IOMMUMemoryRegion *iommu_mr; + Error *err = NULL; if (!memory_region_is_iommu(section->mr)) { return; @@ -696,7 +702,11 @@ static void vhost_iommu_region_add(MemoryListener *listener, iommu->iommu_offset = section->offset_within_address_space - section->offset_within_region; iommu->hdev = dev; - memory_region_register_iommu_notifier(section->mr, &iommu->n); + ret = memory_region_register_iommu_notifier(section->mr, &iommu->n, &err); + if (ret) { + error_report_err(err); + exit(1); + } QLIST_INSERT_HEAD(&dev->iommu_list, iommu, iommu_next); /* TODO: can replay help performance here? */ } diff --git a/hw/xen/trace-events b/hw/xen/trace-events index bc82ecb1a5..e6885bc751 100644 --- a/hw/xen/trace-events +++ b/hw/xen/trace-events @@ -17,11 +17,12 @@ xen_domid_restrict(int err) "err: %u" xen_bus_realize(void) "" xen_bus_unrealize(void) "" xen_bus_enumerate(void) "" +xen_bus_cleanup(void) "" xen_bus_type_enumerate(const char *type) "type: %s" xen_bus_backend_create(const char *type, const char *path) "type: %s path: %s" -xen_bus_add_watch(const char *node, const char *key, char *token) "node: %s key: %s token: %s" -xen_bus_remove_watch(const char *node, const char *key, char *token) "node: %s key: %s token: %s" -xen_bus_watch(const char *token) "token: %s" +xen_bus_device_cleanup(const char *type, char *name) "type: %s name: %s" +xen_bus_add_watch(const char *node, const char *key) "node: %s key: %s" +xen_bus_remove_watch(const char *node, const char *key) "node: %s key: %s" xen_device_realize(const char *type, char *name) "type: %s name: %s" xen_device_unrealize(const char *type, char *name) "type: %s name: %s" xen_device_backend_state(const char *type, char *name, const char *state) "type: %s name: %s -> %s" @@ -30,6 +31,8 @@ xen_device_backend_changed(const char *type, char *name) "type: %s name: %s" xen_device_frontend_state(const char *type, char *name, const char *state) "type: %s name: %s -> %s" xen_device_frontend_changed(const char *type, char *name) "type: %s name: %s" xen_device_unplug(const char *type, char *name) "type: %s name: %s" +xen_device_add_watch(const char *type, char *name, const char *node, const char *key) "type: %s name: %s node: %s key: %s" +xen_device_remove_watch(const char *type, char *name, const char *node, const char *key) "type: %s name: %s node: %s key: %s" # xen-bus-helper.c xs_node_create(const char *node) "%s" diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c index a04478ad4f..c2ad22a42d 100644 --- a/hw/xen/xen-bus.c +++ b/hw/xen/xen-bus.c @@ -157,18 +157,60 @@ static void free_watch(XenWatch *watch) g_free(watch); } -static XenWatch *xen_bus_add_watch(XenBus *xenbus, const char *node, - const char *key, XenWatchHandler handler, - void *opaque, Error **errp) +struct XenWatchList { + struct xs_handle *xsh; + NotifierList notifiers; +}; + +static void watch_list_event(void *opaque) +{ + XenWatchList *watch_list = opaque; + char **v; + const char *token; + + v = xs_check_watch(watch_list->xsh); + if (!v) { + return; + } + + token = v[XS_WATCH_TOKEN]; + + notifier_list_notify(&watch_list->notifiers, (void *)token); + + free(v); +} + +static XenWatchList *watch_list_create(struct xs_handle *xsh) +{ + XenWatchList *watch_list = g_new0(XenWatchList, 1); + + g_assert(xsh); + + watch_list->xsh = xsh; + notifier_list_init(&watch_list->notifiers); + qemu_set_fd_handler(xs_fileno(watch_list->xsh), watch_list_event, NULL, + watch_list); + + return watch_list; +} + +static void watch_list_destroy(XenWatchList *watch_list) +{ + g_assert(notifier_list_empty(&watch_list->notifiers)); + qemu_set_fd_handler(xs_fileno(watch_list->xsh), NULL, NULL, NULL); + g_free(watch_list); +} + +static XenWatch *watch_list_add(XenWatchList *watch_list, const char *node, + const char *key, XenWatchHandler handler, + void *opaque, Error **errp) { XenWatch *watch = new_watch(node, key, handler, opaque); Error *local_err = NULL; - trace_xen_bus_add_watch(watch->node, watch->key, watch->token); - - notifier_list_add(&xenbus->watch_notifiers, &watch->notifier); + notifier_list_add(&watch_list->notifiers, &watch->notifier); - xs_node_watch(xenbus->xsh, node, key, watch->token, &local_err); + xs_node_watch(watch_list->xsh, node, key, watch->token, &local_err); if (local_err) { error_propagate(errp, local_err); @@ -181,18 +223,34 @@ static XenWatch *xen_bus_add_watch(XenBus *xenbus, const char *node, return watch; } -static void xen_bus_remove_watch(XenBus *xenbus, XenWatch *watch, - Error **errp) +static void watch_list_remove(XenWatchList *watch_list, XenWatch *watch, + Error **errp) { - trace_xen_bus_remove_watch(watch->node, watch->key, watch->token); - - xs_node_unwatch(xenbus->xsh, watch->node, watch->key, watch->token, + xs_node_unwatch(watch_list->xsh, watch->node, watch->key, watch->token, errp); notifier_remove(&watch->notifier); free_watch(watch); } +static XenWatch *xen_bus_add_watch(XenBus *xenbus, const char *node, + const char *key, XenWatchHandler handler, + Error **errp) +{ + trace_xen_bus_add_watch(node, key); + + return watch_list_add(xenbus->watch_list, node, key, handler, xenbus, + errp); +} + +static void xen_bus_remove_watch(XenBus *xenbus, XenWatch *watch, + Error **errp) +{ + trace_xen_bus_remove_watch(watch->node, watch->key); + + watch_list_remove(xenbus->watch_list, watch, errp); +} + static void xen_bus_backend_create(XenBus *xenbus, const char *type, const char *name, char *path, Error **errp) @@ -282,13 +340,18 @@ static void xen_bus_type_enumerate(XenBus *xenbus, const char *type) for (i = 0; i < n; i++) { char *backend_path = g_strdup_printf("%s/%s", domain_path, backend[i]); - enum xenbus_state backend_state; + enum xenbus_state state; + unsigned int online; if (xs_node_scanf(xenbus->xsh, XBT_NULL, backend_path, "state", - NULL, "%u", &backend_state) != 1) - backend_state = XenbusStateUnknown; + NULL, "%u", &state) != 1) + state = XenbusStateUnknown; - if (backend_state == XenbusStateInitialising) { + if (xs_node_scanf(xenbus->xsh, XBT_NULL, backend_path, "online", + NULL, "%u", &online) != 1) + online = 0; + + if (online && state == XenbusStateInitialising) { Error *local_err = NULL; xen_bus_backend_create(xenbus, type, backend[i], backend_path, @@ -307,9 +370,8 @@ out: g_free(domain_path); } -static void xen_bus_enumerate(void *opaque) +static void xen_bus_enumerate(XenBus *xenbus) { - XenBus *xenbus = opaque; char **type; unsigned int i, n; @@ -327,46 +389,64 @@ static void xen_bus_enumerate(void *opaque) free(type); } -static void xen_bus_unrealize(BusState *bus, Error **errp) +static void xen_bus_device_cleanup(XenDevice *xendev) { - XenBus *xenbus = XEN_BUS(bus); + const char *type = object_get_typename(OBJECT(xendev)); + Error *local_err = NULL; - trace_xen_bus_unrealize(); + trace_xen_bus_device_cleanup(type, xendev->name); - if (xenbus->backend_watch) { - xen_bus_remove_watch(xenbus, xenbus->backend_watch, NULL); - xenbus->backend_watch = NULL; + g_assert(!xendev->backend_online); + + if (!xen_backend_try_device_destroy(xendev, &local_err)) { + object_unparent(OBJECT(xendev)); } - if (!xenbus->xsh) { - return; + if (local_err) { + error_report_err(local_err); } +} - qemu_set_fd_handler(xs_fileno(xenbus->xsh), NULL, NULL, NULL); +static void xen_bus_cleanup(XenBus *xenbus) +{ + XenDevice *xendev, *next; + + trace_xen_bus_cleanup(); - xs_close(xenbus->xsh); + QLIST_FOREACH_SAFE(xendev, &xenbus->inactive_devices, list, next) { + g_assert(xendev->inactive); + QLIST_REMOVE(xendev, list); + xen_bus_device_cleanup(xendev); + } } -static void xen_bus_watch(void *opaque) +static void xen_bus_backend_changed(void *opaque) { XenBus *xenbus = opaque; - char **v; - const char *token; - g_assert(xenbus->xsh); + xen_bus_enumerate(xenbus); + xen_bus_cleanup(xenbus); +} - v = xs_check_watch(xenbus->xsh); - if (!v) { - return; - } +static void xen_bus_unrealize(BusState *bus, Error **errp) +{ + XenBus *xenbus = XEN_BUS(bus); - token = v[XS_WATCH_TOKEN]; + trace_xen_bus_unrealize(); - trace_xen_bus_watch(token); + if (xenbus->backend_watch) { + xen_bus_remove_watch(xenbus, xenbus->backend_watch, NULL); + xenbus->backend_watch = NULL; + } - notifier_list_notify(&xenbus->watch_notifiers, (void *)token); + if (xenbus->watch_list) { + watch_list_destroy(xenbus->watch_list); + xenbus->watch_list = NULL; + } - free(v); + if (xenbus->xsh) { + xs_close(xenbus->xsh); + } } static void xen_bus_realize(BusState *bus, Error **errp) @@ -390,15 +470,13 @@ static void xen_bus_realize(BusState *bus, Error **errp) xenbus->backend_id = 0; /* Assume lack of node means dom0 */ } - notifier_list_init(&xenbus->watch_notifiers); - qemu_set_fd_handler(xs_fileno(xenbus->xsh), xen_bus_watch, NULL, - xenbus); + xenbus->watch_list = watch_list_create(xenbus->xsh); module_call_init(MODULE_INIT_XEN_BACKEND); xenbus->backend_watch = xen_bus_add_watch(xenbus, "", /* domain root node */ - "backend", xen_bus_enumerate, xenbus, &local_err); + "backend", xen_bus_backend_changed, &local_err); if (local_err) { /* This need not be treated as a hard error so don't propagate */ error_reportf_err(local_err, @@ -520,9 +598,9 @@ static void xen_device_backend_set_online(XenDevice *xendev, bool online) * Tell from the state whether the frontend is likely alive, * i.e. it will react to a change of state of the backend. */ -static bool xen_device_state_is_active(enum xenbus_state state) +static bool xen_device_frontend_is_active(XenDevice *xendev) { - switch (state) { + switch (xendev->frontend_state) { case XenbusStateInitWait: case XenbusStateInitialised: case XenbusStateConnected: @@ -559,33 +637,59 @@ static void xen_device_backend_changed(void *opaque) * state to Closing, but there is no active frontend then set the * backend state to Closed. */ - if (xendev->backend_state == XenbusStateClosing && - !xen_device_state_is_active(state)) { + if (state == XenbusStateClosing && + !xen_device_frontend_is_active(xendev)) { xen_device_backend_set_state(xendev, XenbusStateClosed); } /* * If a backend is still 'online' then we should leave it alone but, - * if a backend is not 'online', then the device should be destroyed - * once the state is Closed. + * if a backend is not 'online', then the device is a candidate + * for destruction. Hence add it to the 'inactive' list to be cleaned + * by xen_bus_cleanup(). */ - if (!xendev->backend_online && - (xendev->backend_state == XenbusStateClosed || - xendev->backend_state == XenbusStateInitialising || - xendev->backend_state == XenbusStateInitWait || - xendev->backend_state == XenbusStateUnknown)) { - Error *local_err = NULL; + if (!online && + (state == XenbusStateClosed || state == XenbusStateInitialising || + state == XenbusStateInitWait || state == XenbusStateUnknown) && + !xendev->inactive) { + XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); - if (!xen_backend_try_device_destroy(xendev, &local_err)) { - object_unparent(OBJECT(xendev)); - } + xendev->inactive = true; + QLIST_INSERT_HEAD(&xenbus->inactive_devices, xendev, list); - if (local_err) { - error_report_err(local_err); - } + /* + * Re-write the state to cause a XenBus backend_watch notification, + * resulting in a call to xen_bus_cleanup(). + */ + xen_device_backend_printf(xendev, "state", "%u", state); } } +static XenWatch *xen_device_add_watch(XenDevice *xendev, const char *node, + const char *key, + XenWatchHandler handler, + Error **errp) +{ + const char *type = object_get_typename(OBJECT(xendev)); + + trace_xen_device_add_watch(type, xendev->name, node, key); + + return watch_list_add(xendev->watch_list, node, key, handler, xendev, + errp); +} + +static void xen_device_remove_watch(XenDevice *xendev, XenWatch *watch, + Error **errp) +{ + const char *type = object_get_typename(OBJECT(xendev)); + + trace_xen_device_remove_watch(type, xendev->name, watch->node, + watch->key); + + watch_list_remove(xendev->watch_list, watch, errp); +} + + static void xen_device_backend_create(XenDevice *xendev, Error **errp) { XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); @@ -610,9 +714,9 @@ static void xen_device_backend_create(XenDevice *xendev, Error **errp) } xendev->backend_state_watch = - xen_bus_add_watch(xenbus, xendev->backend_path, - "state", xen_device_backend_changed, - xendev, &local_err); + xen_device_add_watch(xendev, xendev->backend_path, + "state", xen_device_backend_changed, + &local_err); if (local_err) { error_propagate_prepend(errp, local_err, "failed to watch backend state: "); @@ -620,9 +724,9 @@ static void xen_device_backend_create(XenDevice *xendev, Error **errp) } xendev->backend_online_watch = - xen_bus_add_watch(xenbus, xendev->backend_path, - "online", xen_device_backend_changed, - xendev, &local_err); + xen_device_add_watch(xendev, xendev->backend_path, + "online", xen_device_backend_changed, + &local_err); if (local_err) { error_propagate_prepend(errp, local_err, "failed to watch backend online: "); @@ -636,12 +740,12 @@ static void xen_device_backend_destroy(XenDevice *xendev) Error *local_err = NULL; if (xendev->backend_online_watch) { - xen_bus_remove_watch(xenbus, xendev->backend_online_watch, NULL); + xen_device_remove_watch(xendev, xendev->backend_online_watch, NULL); xendev->backend_online_watch = NULL; } if (xendev->backend_state_watch) { - xen_bus_remove_watch(xenbus, xendev->backend_state_watch, NULL); + xen_device_remove_watch(xendev, xendev->backend_state_watch, NULL); xendev->backend_state_watch = NULL; } @@ -753,6 +857,13 @@ static void xen_device_frontend_changed(void *opaque) } } +static bool xen_device_frontend_exists(XenDevice *xendev) +{ + enum xenbus_state state; + + return (xen_device_frontend_scanf(xendev, "state", "%u", &state) == 1); +} + static void xen_device_frontend_create(XenDevice *xendev, Error **errp) { XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); @@ -761,24 +872,30 @@ static void xen_device_frontend_create(XenDevice *xendev, Error **errp) xendev->frontend_path = xen_device_get_frontend_path(xendev); - perms[0].id = xendev->frontend_id; - perms[0].perms = XS_PERM_NONE; - perms[1].id = xenbus->backend_id; - perms[1].perms = XS_PERM_READ | XS_PERM_WRITE; + /* + * The frontend area may have already been created by a legacy + * toolstack. + */ + if (!xen_device_frontend_exists(xendev)) { + perms[0].id = xendev->frontend_id; + perms[0].perms = XS_PERM_NONE; + perms[1].id = xenbus->backend_id; + perms[1].perms = XS_PERM_READ | XS_PERM_WRITE; - g_assert(xenbus->xsh); + g_assert(xenbus->xsh); - xs_node_create(xenbus->xsh, XBT_NULL, xendev->frontend_path, perms, - ARRAY_SIZE(perms), &local_err); - if (local_err) { - error_propagate_prepend(errp, local_err, - "failed to create frontend: "); - return; + xs_node_create(xenbus->xsh, XBT_NULL, xendev->frontend_path, perms, + ARRAY_SIZE(perms), &local_err); + if (local_err) { + error_propagate_prepend(errp, local_err, + "failed to create frontend: "); + return; + } } xendev->frontend_state_watch = - xen_bus_add_watch(xenbus, xendev->frontend_path, "state", - xen_device_frontend_changed, xendev, &local_err); + xen_device_add_watch(xendev, xendev->frontend_path, "state", + xen_device_frontend_changed, &local_err); if (local_err) { error_propagate_prepend(errp, local_err, "failed to watch frontend state: "); @@ -791,7 +908,8 @@ static void xen_device_frontend_destroy(XenDevice *xendev) Error *local_err = NULL; if (xendev->frontend_state_watch) { - xen_bus_remove_watch(xenbus, xendev->frontend_state_watch, NULL); + xen_device_remove_watch(xendev, xendev->frontend_state_watch, + NULL); xendev->frontend_state_watch = NULL; } @@ -1087,6 +1205,16 @@ static void xen_device_unrealize(DeviceState *dev, Error **errp) xendev->xgth = NULL; } + if (xendev->watch_list) { + watch_list_destroy(xendev->watch_list); + xendev->watch_list = NULL; + } + + if (xendev->xsh) { + xs_close(xendev->xsh); + xendev->xsh = NULL; + } + g_free(xendev->name); xendev->name = NULL; } @@ -1129,6 +1257,14 @@ static void xen_device_realize(DeviceState *dev, Error **errp) trace_xen_device_realize(type, xendev->name); + xendev->xsh = xs_open(0); + if (!xendev->xsh) { + error_setg_errno(errp, errno, "failed xs_open"); + goto unrealize; + } + + xendev->watch_list = watch_list_create(xendev->xsh); + xendev->xgth = xengnttab_open(NULL, 0); if (!xendev->xgth) { error_setg_errno(errp, errno, "failed xengnttab_open"); @@ -1167,12 +1303,14 @@ static void xen_device_realize(DeviceState *dev, Error **errp) xen_device_backend_set_online(xendev, true); xen_device_backend_set_state(xendev, XenbusStateInitWait); - xen_device_frontend_printf(xendev, "backend", "%s", - xendev->backend_path); - xen_device_frontend_printf(xendev, "backend-id", "%u", - xenbus->backend_id); + if (!xen_device_frontend_exists(xendev)) { + xen_device_frontend_printf(xendev, "backend", "%s", + xendev->backend_path); + xen_device_frontend_printf(xendev, "backend-id", "%u", + xenbus->backend_id); - xen_device_frontend_set_state(xendev, XenbusStateInitialising, true); + xen_device_frontend_set_state(xendev, XenbusStateInitialising, true); + } xendev->exit.notify = xen_device_exit; qemu_add_exit_notifier(&xendev->exit); diff --git a/include/block/nbd.h b/include/block/nbd.h index 21550747cf..316fd705a9 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -340,6 +340,7 @@ void nbd_export_put(NBDExport *exp); BlockBackend *nbd_export_get_blockdev(NBDExport *exp); +AioContext *nbd_export_aio_context(NBDExport *exp); NBDExport *nbd_export_find(const char *name); void nbd_export_close_all(void); diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index d2d443c4f9..ad9ab85eb3 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -317,26 +317,35 @@ CPUArchState *cpu_copy(CPUArchState *env); #if !defined(CONFIG_USER_ONLY) -/* Flags stored in the low bits of the TLB virtual address. These are - * defined so that fast path ram access is all zeros. +/* + * Flags stored in the low bits of the TLB virtual address. + * These are defined so that fast path ram access is all zeros. * The flags all must be between TARGET_PAGE_BITS and * maximum address alignment bit. + * + * Use TARGET_PAGE_BITS_MIN so that these bits are constant + * when TARGET_PAGE_BITS_VARY is in effect. */ /* Zero if TLB entry is valid. */ -#define TLB_INVALID_MASK (1 << (TARGET_PAGE_BITS - 1)) +#define TLB_INVALID_MASK (1 << (TARGET_PAGE_BITS_MIN - 1)) /* Set if TLB entry references a clean RAM page. The iotlb entry will contain the page physical address. */ -#define TLB_NOTDIRTY (1 << (TARGET_PAGE_BITS - 2)) +#define TLB_NOTDIRTY (1 << (TARGET_PAGE_BITS_MIN - 2)) /* Set if TLB entry is an IO callback. */ -#define TLB_MMIO (1 << (TARGET_PAGE_BITS - 3)) +#define TLB_MMIO (1 << (TARGET_PAGE_BITS_MIN - 3)) /* Set if TLB entry contains a watchpoint. */ -#define TLB_WATCHPOINT (1 << (TARGET_PAGE_BITS - 4)) +#define TLB_WATCHPOINT (1 << (TARGET_PAGE_BITS_MIN - 4)) +/* Set if TLB entry requires byte swap. */ +#define TLB_BSWAP (1 << (TARGET_PAGE_BITS_MIN - 5)) +/* Set if TLB entry writes ignored. */ +#define TLB_DISCARD_WRITE (1 << (TARGET_PAGE_BITS_MIN - 6)) /* Use this mask to check interception with an alignment mask * in a TCG backend. */ #define TLB_FLAGS_MASK \ - (TLB_INVALID_MASK | TLB_NOTDIRTY | TLB_MMIO | TLB_WATCHPOINT) + (TLB_INVALID_MASK | TLB_NOTDIRTY | TLB_MMIO \ + | TLB_WATCHPOINT | TLB_BSWAP | TLB_DISCARD_WRITE) /** * tlb_hit_page: return true if page aligned @addr is a hit against the diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index f7dbe75fbc..81753bbb34 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -100,9 +100,6 @@ void qemu_flush_coalesced_mmio_buffer(void); void cpu_flush_icache_range(hwaddr start, hwaddr len); -extern struct MemoryRegion io_mem_rom; -extern struct MemoryRegion io_mem_notdirty; - typedef int (RAMBlockIterFunc)(RAMBlock *rb, void *opaque); int qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque); diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 81b02eb2fe..49db07ba0b 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -509,11 +509,7 @@ address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr, hwaddr *xlat, hwaddr *plen, MemTxAttrs attrs, int *prot); hwaddr memory_region_section_get_iotlb(CPUState *cpu, - MemoryRegionSection *section, - target_ulong vaddr, - hwaddr paddr, hwaddr xlat, - int prot, - target_ulong *address); + MemoryRegionSection *section); #endif /* vl.c */ diff --git a/include/exec/memory-internal.h b/include/exec/memory-internal.h index ef4fb92371..9fcc2af25c 100644 --- a/include/exec/memory-internal.h +++ b/include/exec/memory-internal.h @@ -49,70 +49,5 @@ void address_space_dispatch_free(AddressSpaceDispatch *d); void mtree_print_dispatch(struct AddressSpaceDispatch *d, MemoryRegion *root); - -struct page_collection; - -/* Opaque struct for passing info from memory_notdirty_write_prepare() - * to memory_notdirty_write_complete(). Callers should treat all fields - * as private, with the exception of @active. - * - * @active is a field which is not touched by either the prepare or - * complete functions, but which the caller can use if it wishes to - * track whether it has called prepare for this struct and so needs - * to later call the complete function. - */ -typedef struct { - CPUState *cpu; - struct page_collection *pages; - ram_addr_t ram_addr; - vaddr mem_vaddr; - unsigned size; - bool active; -} NotDirtyInfo; - -/** - * memory_notdirty_write_prepare: call before writing to non-dirty memory - * @ndi: pointer to opaque NotDirtyInfo struct - * @cpu: CPU doing the write - * @mem_vaddr: virtual address of write - * @ram_addr: the ram address of the write - * @size: size of write in bytes - * - * Any code which writes to the host memory corresponding to - * guest RAM which has been marked as NOTDIRTY must wrap those - * writes in calls to memory_notdirty_write_prepare() and - * memory_notdirty_write_complete(): - * - * NotDirtyInfo ndi; - * memory_notdirty_write_prepare(&ndi, ....); - * ... perform write here ... - * memory_notdirty_write_complete(&ndi); - * - * These calls will ensure that we flush any TCG translated code for - * the memory being written, update the dirty bits and (if possible) - * remove the slowpath callback for writing to the memory. - * - * This must only be called if we are using TCG; it will assert otherwise. - * - * We may take locks in the prepare call, so callers must ensure that - * they don't exit (via longjump or otherwise) without calling complete. - * - * This call must only be made inside an RCU critical section. - * (Note that while we're executing a TCG TB we're always in an - * RCU critical section, which is likely to be the case for callers - * of these functions.) - */ -void memory_notdirty_write_prepare(NotDirtyInfo *ndi, - CPUState *cpu, - vaddr mem_vaddr, - ram_addr_t ram_addr, - unsigned size); -/** - * memory_notdirty_write_complete: finish write to non-dirty memory - * @ndi: pointer to the opaque NotDirtyInfo struct which was initialized - * by memory_not_dirty_write_prepare(). - */ -void memory_notdirty_write_complete(NotDirtyInfo *ndi); - #endif #endif diff --git a/include/exec/memory.h b/include/exec/memory.h index a30245c25a..e499dc215b 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -288,10 +288,16 @@ typedef struct IOMMUMemoryRegionClass { * @iommu: the IOMMUMemoryRegion * @old_flags: events which previously needed to be notified * @new_flags: events which now need to be notified + * + * Returns 0 on success, or a negative errno; in particular + * returns -EINVAL if the new flag bitmap is not supported by the + * IOMMU memory region. In case of failure, the error object + * must be created */ - void (*notify_flag_changed)(IOMMUMemoryRegion *iommu, - IOMMUNotifierFlag old_flags, - IOMMUNotifierFlag new_flags); + int (*notify_flag_changed)(IOMMUMemoryRegion *iommu, + IOMMUNotifierFlag old_flags, + IOMMUNotifierFlag new_flags, + Error **errp); /* Called to handle memory_region_iommu_replay(). * * The default implementation of memory_region_iommu_replay() is to @@ -495,15 +501,27 @@ static inline FlatView *address_space_to_flatview(AddressSpace *as) * @nonvolatile: this section is non-volatile */ struct MemoryRegionSection { + Int128 size; MemoryRegion *mr; FlatView *fv; hwaddr offset_within_region; - Int128 size; hwaddr offset_within_address_space; bool readonly; bool nonvolatile; }; +static inline bool MemoryRegionSection_eq(MemoryRegionSection *a, + MemoryRegionSection *b) +{ + return a->mr == b->mr && + a->fv == b->fv && + a->offset_within_region == b->offset_within_region && + a->offset_within_address_space == b->offset_within_address_space && + int128_eq(a->size, b->size) && + a->readonly == b->readonly && + a->nonvolatile == b->nonvolatile; +} + /** * memory_region_init: Initialize a memory region * @@ -1067,13 +1085,18 @@ void memory_region_notify_one(IOMMUNotifier *notifier, * memory_region_register_iommu_notifier: register a notifier for changes to * IOMMU translation entries. * + * Returns 0 on success, or a negative errno otherwise. In particular, + * -EINVAL indicates that at least one of the attributes of the notifier + * is not supported (flag/range) by the IOMMU memory region. In case of error + * the error object must be created. + * * @mr: the memory region to observe * @n: the IOMMUNotifier to be added; the notify callback receives a * pointer to an #IOMMUTLBEntry as the opaque value; the pointer * ceases to be valid on exit from the notifier. */ -void memory_region_register_iommu_notifier(MemoryRegion *mr, - IOMMUNotifier *n); +int memory_region_register_iommu_notifier(MemoryRegion *mr, + IOMMUNotifier *n, Error **errp); /** * memory_region_iommu_replay: replay existing IOMMU translations to diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index a327a80cfe..e96e621de5 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -44,12 +44,6 @@ struct RAMBlock { size_t page_size; /* dirty bitmap used during migration */ unsigned long *bmap; - /* bitmap of pages that haven't been sent even once - * only maintained and used in postcopy at the moment - * where it's used to send the dirtymap at the start - * of the postcopy phase - */ - unsigned long *unsentmap; /* bitmap of already received pages in postcopy */ unsigned long *receivedmap; diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index c7cda65c66..031f587e51 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -338,7 +338,6 @@ struct qemu_work_item; * @next_cpu: Next CPU sharing TB cache. * @opaque: User data. * @mem_io_pc: Host Program Counter at which the memory was accessed. - * @mem_io_vaddr: Target virtual address at which the memory was accessed. * @kvm_fd: vCPU file descriptor for KVM. * @work_mutex: Lock to prevent multiple access to queued_work_*. * @queued_work_first: First asynchronous work pending. @@ -413,7 +412,6 @@ struct CPUState { * we store some rarely used information in the CPU context. */ uintptr_t mem_io_pc; - vaddr mem_io_vaddr; /* * This is only needed for the legacy cpu_unassigned_access() hook; * when all targets using it have been converted to use diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h index abd87605b2..23506f05d9 100644 --- a/include/hw/pci-host/spapr.h +++ b/include/hw/pci-host/spapr.h @@ -128,13 +128,6 @@ struct SpaprPhbState { #define SPAPR_PCI_NV2ATSD_WIN_SIZE (NVGPU_MAX_NUM * NVGPU_MAX_LINKS * \ 64 * KiB) -static inline qemu_irq spapr_phb_lsi_qirq(struct SpaprPhbState *phb, int pin) -{ - SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); - - return spapr_qirq(spapr, phb->lsi_table[pin].irq); -} - int spapr_dt_phb(SpaprPhbState *phb, uint32_t intc_phandle, void *fdt, uint32_t nr_msis, int *node_offset); diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h index fb123edc4e..1cdbe55bf8 100644 --- a/include/hw/ppc/pnv.h +++ b/include/hw/ppc/pnv.h @@ -26,6 +26,7 @@ #include "hw/ppc/pnv_lpc.h" #include "hw/ppc/pnv_psi.h" #include "hw/ppc/pnv_occ.h" +#include "hw/ppc/pnv_homer.h" #include "hw/ppc/pnv_xive.h" #include "hw/ppc/pnv_core.h" @@ -76,6 +77,7 @@ typedef struct Pnv8Chip { PnvLpcController lpc; Pnv8Psi psi; PnvOCC occ; + PnvHomer homer; } Pnv8Chip; #define TYPE_PNV9_CHIP "pnv9-chip" @@ -90,6 +92,7 @@ typedef struct Pnv9Chip { Pnv9Psi psi; PnvLpcController lpc; PnvOCC occ; + PnvHomer homer; uint32_t nr_quads; PnvQuad *quads; @@ -198,6 +201,16 @@ void pnv_bmc_powerdown(IPMIBmc *bmc); #define PNV_XSCOM_BASE(chip) \ (0x0003fc0000000000ull + ((uint64_t)(chip)->chip_id) * PNV_XSCOM_SIZE) +#define PNV_OCC_COMMON_AREA_SIZE 0x0000000000700000ull +#define PNV_OCC_COMMON_AREA(chip) \ + (0x7fff800000ull + ((uint64_t)PNV_CHIP_INDEX(chip) * \ + PNV_OCC_COMMON_AREA_SIZE)) + +#define PNV_HOMER_SIZE 0x0000000000300000ull +#define PNV_HOMER_BASE(chip) \ + (0x7ffd800000ull + ((uint64_t)PNV_CHIP_INDEX(chip)) * PNV_HOMER_SIZE) + + /* * XSCOM 0x20109CA defines the ICP BAR: * @@ -256,4 +269,12 @@ void pnv_bmc_powerdown(IPMIBmc *bmc); #define PNV9_XSCOM_SIZE 0x0000000400000000ull #define PNV9_XSCOM_BASE(chip) PNV9_CHIP_BASE(chip, 0x00603fc00000000ull) +#define PNV9_OCC_COMMON_AREA_SIZE 0x0000000000700000ull +#define PNV9_OCC_COMMON_AREA(chip) \ + (0x203fff800000ull + ((uint64_t)PNV_CHIP_INDEX(chip) * \ + PNV9_OCC_COMMON_AREA_SIZE)) + +#define PNV9_HOMER_SIZE 0x0000000000300000ull +#define PNV9_HOMER_BASE(chip) \ + (0x203ffd800000ull + ((uint64_t)PNV_CHIP_INDEX(chip)) * PNV9_HOMER_SIZE) #endif /* PPC_PNV_H */ diff --git a/include/hw/ppc/pnv_homer.h b/include/hw/ppc/pnv_homer.h new file mode 100644 index 0000000000..abaec43c2d --- /dev/null +++ b/include/hw/ppc/pnv_homer.h @@ -0,0 +1,53 @@ +/* + * QEMU PowerPC PowerNV Emulation of a few HOMER related registers + * + * Copyright (c) 2019, IBM Corporation. + * + * 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. + * + * 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/>. + */ + +#ifndef PPC_PNV_HOMER_H +#define PPC_PNV_HOMER_H + +#include "hw/ppc/pnv.h" + +#define TYPE_PNV_HOMER "pnv-homer" +#define PNV_HOMER(obj) OBJECT_CHECK(PnvHomer, (obj), TYPE_PNV_HOMER) +#define TYPE_PNV8_HOMER TYPE_PNV_HOMER "-POWER8" +#define PNV8_HOMER(obj) OBJECT_CHECK(PnvHomer, (obj), TYPE_PNV8_HOMER) +#define TYPE_PNV9_HOMER TYPE_PNV_HOMER "-POWER9" +#define PNV9_HOMER(obj) OBJECT_CHECK(PnvHomer, (obj), TYPE_PNV9_HOMER) + +typedef struct PnvHomer { + DeviceState parent; + + struct PnvChip *chip; + MemoryRegion regs; +} PnvHomer; + +#define PNV_HOMER_CLASS(klass) \ + OBJECT_CLASS_CHECK(PnvHomerClass, (klass), TYPE_PNV_HOMER) +#define PNV_HOMER_GET_CLASS(obj) \ + OBJECT_GET_CLASS(PnvHomerClass, (obj), TYPE_PNV_HOMER) + +typedef struct PnvHomerClass { + DeviceClass parent_class; + + int homer_size; + const MemoryRegionOps *homer_ops; + + hwaddr core_max_base; +} PnvHomerClass; + +#endif /* PPC_PNV_HOMER_H */ diff --git a/include/hw/ppc/pnv_occ.h b/include/hw/ppc/pnv_occ.h index ed0709bfc0..66b0989be6 100644 --- a/include/hw/ppc/pnv_occ.h +++ b/include/hw/ppc/pnv_occ.h @@ -38,6 +38,7 @@ typedef struct PnvOCC { PnvPsi *psi; MemoryRegion xscom_regs; + MemoryRegion sram_regs; } PnvOCC; #define PNV_OCC_CLASS(klass) \ @@ -49,7 +50,9 @@ typedef struct PnvOCCClass { DeviceClass parent_class; int xscom_size; + int sram_size; const MemoryRegionOps *xscom_ops; + const MemoryRegionOps *sram_ops; int psi_irq; } PnvOCCClass; diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 03111fd55b..cbd1a4c9f3 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -154,8 +154,6 @@ struct SpaprMachineState { hwaddr rma_size; int vrma_adjust; - ssize_t rtas_size; - void *rtas_blob; uint32_t fdt_size; uint32_t fdt_initial_size; void *fdt_blob; @@ -175,7 +173,7 @@ struct SpaprMachineState { /* ibm,client-architecture-support option negotiation */ bool cas_reboot; - bool cas_legacy_guest_workaround; + bool cas_pre_isa3_guest; SpaprOptionVector *ov5; /* QEMU-supported option vectors */ SpaprOptionVector *ov5_cas; /* negotiated (via CAS) option vectors */ uint32_t max_compat_pvr; diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h index 5db305165c..69a37f608e 100644 --- a/include/hw/ppc/spapr_irq.h +++ b/include/hw/ppc/spapr_irq.h @@ -16,13 +16,18 @@ * IRQ range offsets per device type */ #define SPAPR_IRQ_IPI 0x0 -#define SPAPR_IRQ_EPOW 0x1000 /* XICS_IRQ_BASE offset */ -#define SPAPR_IRQ_HOTPLUG 0x1001 -#define SPAPR_IRQ_VIO 0x1100 /* 256 VIO devices */ -#define SPAPR_IRQ_PCI_LSI 0x1200 /* 32+ PHBs devices */ -#define SPAPR_IRQ_MSI 0x1300 /* Offset of the dynamic range covered - * by the bitmap allocator */ +#define SPAPR_XIRQ_BASE XICS_IRQ_BASE /* 0x1000 */ +#define SPAPR_IRQ_EPOW (SPAPR_XIRQ_BASE + 0x0000) +#define SPAPR_IRQ_HOTPLUG (SPAPR_XIRQ_BASE + 0x0001) +#define SPAPR_IRQ_VIO (SPAPR_XIRQ_BASE + 0x0100) /* 256 VIO devices */ +#define SPAPR_IRQ_PCI_LSI (SPAPR_XIRQ_BASE + 0x0200) /* 32+ PHBs devices */ + +/* Offset of the dynamic range covered by the bitmap allocator */ +#define SPAPR_IRQ_MSI (SPAPR_XIRQ_BASE + 0x0300) + +#define SPAPR_NR_XIRQS 0x1000 +#define SPAPR_NR_MSIS (SPAPR_XIRQ_BASE + SPAPR_NR_XIRQS - SPAPR_IRQ_MSI) typedef struct SpaprMachineState SpaprMachineState; @@ -32,14 +37,13 @@ int spapr_irq_msi_alloc(SpaprMachineState *spapr, uint32_t num, bool align, void spapr_irq_msi_free(SpaprMachineState *spapr, int irq, uint32_t num); typedef struct SpaprIrq { - uint32_t nr_irqs; + uint32_t nr_xirqs; uint32_t nr_msis; - uint8_t ov5; + bool xics; + bool xive; - void (*init)(SpaprMachineState *spapr, int nr_irqs, Error **errp); int (*claim)(SpaprMachineState *spapr, int irq, bool lsi, Error **errp); - void (*free)(SpaprMachineState *spapr, int irq, int num); - qemu_irq (*qirq)(SpaprMachineState *spapr, int irq); + void (*free)(SpaprMachineState *spapr, int irq); void (*print_info)(SpaprMachineState *spapr, Monitor *mon); void (*dt_populate)(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt, uint32_t phandle); @@ -48,7 +52,6 @@ typedef struct SpaprIrq { int (*post_load)(SpaprMachineState *spapr, int version_id); void (*reset)(SpaprMachineState *spapr, Error **errp); void (*set_irq)(void *opaque, int srcno, int val); - const char *(*get_nodename)(SpaprMachineState *spapr); void (*init_kvm)(SpaprMachineState *spapr, Error **errp); } SpaprIrq; diff --git a/include/hw/ppc/spapr_vio.h b/include/hw/ppc/spapr_vio.h index 875be28cdd..72762ed16b 100644 --- a/include/hw/ppc/spapr_vio.h +++ b/include/hw/ppc/spapr_vio.h @@ -24,6 +24,7 @@ #include "hw/ppc/spapr.h" #include "sysemu/dma.h" +#include "hw/irq.h" #define TYPE_VIO_SPAPR_DEVICE "vio-spapr-device" #define VIO_SPAPR_DEVICE(obj) \ @@ -84,11 +85,11 @@ extern SpaprVioDevice *spapr_vio_find_by_reg(SpaprVioBus *bus, uint32_t reg); void spapr_dt_vdevice(SpaprVioBus *bus, void *fdt); extern gchar *spapr_vio_stdout_path(SpaprVioBus *bus); -static inline qemu_irq spapr_vio_qirq(SpaprVioDevice *dev) +static inline void spapr_vio_irq_pulse(SpaprVioDevice *dev) { SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); - return spapr_qirq(spapr, dev->irq); + qemu_irq_pulse(spapr_qirq(spapr, dev->irq)); } static inline bool spapr_vio_dma_valid(SpaprVioDevice *dev, uint64_t taddr, diff --git a/include/hw/ppc/spapr_xive.h b/include/hw/ppc/spapr_xive.h index bfd40f01d8..0df20a6590 100644 --- a/include/hw/ppc/spapr_xive.h +++ b/include/hw/ppc/spapr_xive.h @@ -54,8 +54,8 @@ typedef struct SpaprXive { */ #define SPAPR_XIVE_BLOCK_ID 0x0 -bool spapr_xive_irq_claim(SpaprXive *xive, uint32_t lisn, bool lsi); -bool spapr_xive_irq_free(SpaprXive *xive, uint32_t lisn); +int spapr_xive_irq_claim(SpaprXive *xive, int lisn, bool lsi, Error **errp); +void spapr_xive_irq_free(SpaprXive *xive, int lisn); void spapr_xive_pic_print_info(SpaprXive *xive, Monitor *mon); int spapr_xive_post_load(SpaprXive *xive, int version_id); diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index f2a8d6a4b4..1e6a9300eb 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -89,27 +89,18 @@ struct PnvICPState { uint32_t links[3]; }; -#define TYPE_ICS_BASE "ics-base" -#define ICS_BASE(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS_BASE) +#define TYPE_ICS "ics" +#define ICS(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS) -/* Retain ics for sPAPR for migration from existing sPAPR guests */ -#define TYPE_ICS_SIMPLE "ics" -#define ICS_SIMPLE(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS_SIMPLE) - -#define ICS_BASE_CLASS(klass) \ - OBJECT_CLASS_CHECK(ICSStateClass, (klass), TYPE_ICS_BASE) -#define ICS_BASE_GET_CLASS(obj) \ - OBJECT_GET_CLASS(ICSStateClass, (obj), TYPE_ICS_BASE) +#define ICS_CLASS(klass) \ + OBJECT_CLASS_CHECK(ICSStateClass, (klass), TYPE_ICS) +#define ICS_GET_CLASS(obj) \ + OBJECT_GET_CLASS(ICSStateClass, (obj), TYPE_ICS) struct ICSStateClass { DeviceClass parent_class; DeviceRealize parent_realize; - DeviceReset parent_reset; - - void (*reject)(ICSState *s, uint32_t irq); - void (*resend)(ICSState *s); - void (*eoi)(ICSState *s, uint32_t irq); }; struct ICSState { @@ -147,13 +138,9 @@ struct ICSIRQState { uint8_t flags; }; -struct XICSFabric { - Object parent; -}; - #define TYPE_XICS_FABRIC "xics-fabric" #define XICS_FABRIC(obj) \ - OBJECT_CHECK(XICSFabric, (obj), TYPE_XICS_FABRIC) + INTERFACE_CHECK(XICSFabric, (obj), TYPE_XICS_FABRIC) #define XICS_FABRIC_CLASS(klass) \ OBJECT_CLASS_CHECK(XICSFabricClass, (klass), TYPE_XICS_FABRIC) #define XICS_FABRIC_GET_CLASS(obj) \ @@ -175,9 +162,14 @@ uint32_t icp_accept(ICPState *ss); uint32_t icp_ipoll(ICPState *ss, uint32_t *mfrr); void icp_eoi(ICPState *icp, uint32_t xirr); -void ics_simple_write_xive(ICSState *ics, int nr, int server, - uint8_t priority, uint8_t saved_priority); -void ics_simple_set_irq(void *opaque, int srcno, int val); +void ics_write_xive(ICSState *ics, int nr, int server, + uint8_t priority, uint8_t saved_priority); +void ics_set_irq(void *opaque, int srcno, int val); + +static inline bool ics_irq_free(ICSState *ics, uint32_t srcno) +{ + return !(ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MASK); +} void ics_set_irq_type(ICSState *ics, int srcno, bool lsi); void icp_pic_print_info(ICPState *icp, Monitor *mon); diff --git a/include/hw/ppc/xics_spapr.h b/include/hw/ppc/xics_spapr.h index 5dabc9a138..0b35e85c26 100644 --- a/include/hw/ppc/xics_spapr.h +++ b/include/hw/ppc/xics_spapr.h @@ -29,13 +29,13 @@ #include "hw/ppc/spapr.h" -#define XICS_NODENAME "interrupt-controller" +#define TYPE_ICS_SPAPR "ics-spapr" +#define ICS_SPAPR(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS_SPAPR) void spapr_dt_xics(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt, uint32_t phandle); int xics_kvm_connect(SpaprMachineState *spapr, Error **errp); void xics_kvm_disconnect(SpaprMachineState *spapr, Error **errp); bool xics_kvm_has_broken_disconnect(SpaprMachineState *spapr); -void xics_spapr_init(SpaprMachineState *spapr); #endif /* XICS_SPAPR_H */ diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h index 6d38755f84..fd3319bd32 100644 --- a/include/hw/ppc/xive.h +++ b/include/hw/ppc/xive.h @@ -425,7 +425,7 @@ static inline uint32_t xive_nvt_cam_line(uint8_t nvt_blk, uint32_t nvt_idx) * KVM XIVE device helpers */ -void kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp); +int kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp); void kvmppc_xive_source_set_irq(void *opaque, int srcno, int val); void kvmppc_xive_cpu_connect(XiveTCTX *tctx, Error **errp); void kvmppc_xive_cpu_synchronize_state(XiveTCTX *tctx, Error **errp); diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 9107bd41c0..fd564209ac 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -71,7 +71,7 @@ typedef struct VFIOContainer { MemoryListener listener; MemoryListener prereg_listener; unsigned iommu_type; - int error; + Error *error; bool initialized; unsigned long pgsizes; QLIST_HEAD(, VFIOGuestIOMMU) giommu_list; diff --git a/include/hw/xen/xen-bus.h b/include/hw/xen/xen-bus.h index 1c2d9dfdb8..3d5532258d 100644 --- a/include/hw/xen/xen-bus.h +++ b/include/hw/xen/xen-bus.h @@ -14,6 +14,7 @@ typedef void (*XenWatchHandler)(void *opaque); +typedef struct XenWatchList XenWatchList; typedef struct XenWatch XenWatch; typedef struct XenEventChannel XenEventChannel; @@ -21,6 +22,8 @@ typedef struct XenDevice { DeviceState qdev; domid_t frontend_id; char *name; + struct xs_handle *xsh; + XenWatchList *watch_list; char *backend_path, *frontend_path; enum xenbus_state backend_state, frontend_state; Notifier exit; @@ -29,7 +32,9 @@ typedef struct XenDevice { XenWatch *backend_online_watch; xengnttab_handle *xgth; bool feature_grant_copy; + bool inactive; QLIST_HEAD(, XenEventChannel) event_channels; + QLIST_ENTRY(XenDevice) list; } XenDevice; typedef char *(*XenDeviceGetName)(XenDevice *xendev, Error **errp); @@ -63,8 +68,9 @@ typedef struct XenBus { BusState qbus; domid_t backend_id; struct xs_handle *xsh; - NotifierList watch_notifiers; + XenWatchList *watch_list; XenWatch *backend_watch; + QLIST_HEAD(, XenDevice) inactive_devices; } XenBus; typedef struct XenBusClass { diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h index 5b2ed3f202..c5b23851a1 100644 --- a/include/qapi/visitor.h +++ b/include/qapi/visitor.h @@ -364,10 +364,10 @@ void visit_start_list(Visitor *v, const char *name, GenericList **list, * @tail must not be NULL; on the first call, @tail is the value of * *list after visit_start_list(), and on subsequent calls @tail must * be the previously returned value. Should be called in a loop until - * a NULL return or error occurs; for each non-NULL return, the caller - * then calls the appropriate visit_type_*() for the element type of - * the list, with that function's name parameter set to NULL and obj - * set to the address of @tail->value. + * a NULL return; for each non-NULL return, the caller then calls the + * appropriate visit_type_*() for the element type of the list, with + * that function's name parameter set to NULL and obj set to the + * address of @tail->value. */ GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size); diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h index 09fc44cca4..7b93c73340 100644 --- a/include/qemu/compiler.h +++ b/include/qemu/compiler.h @@ -170,6 +170,17 @@ # define QEMU_NONSTRING #endif +/* + * Forced inlining may be desired to encourage constant propagation + * of function parameters. However, it can also make debugging harder, + * so disable it for a non-optimizing build. + */ +#if defined(__OPTIMIZE__) +#define QEMU_ALWAYS_INLINE __attribute__((always_inline)) +#else +#define QEMU_ALWAYS_INLINE +#endif + /* Implement C11 _Generic via GCC builtins. Example: * * QEMU_GENERIC(x, (float, sinf), (long double, sinl), sin) (x) @@ -210,4 +221,19 @@ #define QEMU_GENERIC9(x, a0, ...) QEMU_GENERIC_IF(x, a0, QEMU_GENERIC8(x, __VA_ARGS__)) #define QEMU_GENERIC10(x, a0, ...) QEMU_GENERIC_IF(x, a0, QEMU_GENERIC9(x, __VA_ARGS__)) +/** + * qemu_build_not_reached() + * + * The compiler, during optimization, is expected to prove that a call + * to this function cannot be reached and remove it. If the compiler + * supports QEMU_ERROR, this will be reported at compile time; otherwise + * this will be reported at link time due to the missing symbol. + */ +#ifdef __OPTIMIZE__ +extern void QEMU_NORETURN QEMU_ERROR("code path is reachable") + qemu_build_not_reached(void); +#else +#define qemu_build_not_reached() g_assert_not_reached() +#endif + #endif /* COMPILER_H */ diff --git a/include/qemu/notify.h b/include/qemu/notify.h index a3d73e4bc7..bcfa70fb2e 100644 --- a/include/qemu/notify.h +++ b/include/qemu/notify.h @@ -40,6 +40,8 @@ void notifier_remove(Notifier *notifier); void notifier_list_notify(NotifierList *list, void *data); +bool notifier_list_empty(NotifierList *list); + /* Same as Notifier but allows .notify() to return errors */ typedef struct NotifierWithReturn NotifierWithReturn; diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index fd674772ab..9d143282bc 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -462,7 +462,7 @@ int kvm_vm_check_extension(KVMState *s, unsigned int extension); uint32_t kvm_arch_get_supported_cpuid(KVMState *env, uint32_t function, uint32_t index, int reg); -uint32_t kvm_arch_get_supported_msr_feature(KVMState *s, uint32_t index); +uint64_t kvm_arch_get_supported_msr_feature(KVMState *s, uint32_t index); void kvm_set_sigmask_len(KVMState *s, unsigned int sigmask_len); diff --git a/include/sysemu/kvm_int.h b/include/sysemu/kvm_int.h index 72b2d1b3ae..ac2d1f8b56 100644 --- a/include/sysemu/kvm_int.h +++ b/include/sysemu/kvm_int.h @@ -41,4 +41,5 @@ typedef struct KVMMemoryListener { void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml, AddressSpace *as, int as_id); +void kvm_set_max_memslot_size(hwaddr max_slot_size); #endif diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c index 8d65de5b9f..e28c45cd4a 100644 --- a/linux-user/arm/cpu_loop.c +++ b/linux-user/arm/cpu_loop.c @@ -325,9 +325,6 @@ void cpu_loop(CPUARMState *env) if (n == ARM_NR_cacheflush) { /* nop */ - } else if (n == ARM_NR_semihosting - || n == ARM_NR_thumb_semihosting) { - env->regs[0] = do_arm_semihosting (env); } else if (n == 0 || n >= ARM_SYSCALL_BASE || env->thumb) { /* linux syscall */ if (env->thumb || n == 0) { diff --git a/linux-user/arm/target_syscall.h b/linux-user/arm/target_syscall.h index afc0772e19..f85cbdaf56 100644 --- a/linux-user/arm/target_syscall.h +++ b/linux-user/arm/target_syscall.h @@ -18,9 +18,6 @@ struct target_pt_regs { #define ARM_NR_set_tls (ARM_NR_BASE + 5) #define ARM_NR_get_tls (ARM_NR_BASE + 6) -#define ARM_NR_semihosting 0x123456 -#define ARM_NR_thumb_semihosting 0xAB - #if defined(TARGET_WORDS_BIGENDIAN) #define UNAME_MACHINE "armv5teb" #else diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c index 619a56950d..5b82af6cb6 100644 --- a/linux-user/ppc/signal.c +++ b/linux-user/ppc/signal.c @@ -501,8 +501,10 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, int i, err = 0; #if defined(TARGET_PPC64) struct target_sigcontext *sc = 0; +#if !defined(TARGET_ABI32) struct image_info *image = ((TaskState *)thread_cpu->opaque)->info; #endif +#endif rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf)); if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1)) @@ -557,7 +559,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, env->gpr[5] = (target_ulong) h2g(&rt_sf->uc); env->gpr[6] = (target_ulong) h2g(rt_sf); -#if defined(TARGET_PPC64) +#if defined(TARGET_PPC64) && !defined(TARGET_ABI32) if (get_ppc64_abi(image) < 2) { /* ELFv1 PPC64 function pointers are pointers to OPD entries. */ struct target_func_ptr *handler = @@ -434,11 +434,6 @@ static MemTxResult memory_region_read_accessor(MemoryRegion *mr, tmp = mr->ops->read(mr->opaque, addr, size); if (mr->subpage) { trace_memory_region_subpage_read(get_cpu_index(), mr, addr, tmp, size); - } else if (mr == &io_mem_notdirty) { - /* Accesses to code which has previously been translated into a TB show - * up in the MMIO path, as accesses to the io_mem_notdirty - * MemoryRegion. */ - trace_memory_region_tb_read(get_cpu_index(), addr, tmp, size); } else if (TRACE_MEMORY_REGION_OPS_READ_ENABLED) { hwaddr abs_addr = memory_region_to_absolute_addr(mr, addr); trace_memory_region_ops_read(get_cpu_index(), mr, abs_addr, tmp, size); @@ -461,11 +456,6 @@ static MemTxResult memory_region_read_with_attrs_accessor(MemoryRegion *mr, r = mr->ops->read_with_attrs(mr->opaque, addr, &tmp, size, attrs); if (mr->subpage) { trace_memory_region_subpage_read(get_cpu_index(), mr, addr, tmp, size); - } else if (mr == &io_mem_notdirty) { - /* Accesses to code which has previously been translated into a TB show - * up in the MMIO path, as accesses to the io_mem_notdirty - * MemoryRegion. */ - trace_memory_region_tb_read(get_cpu_index(), addr, tmp, size); } else if (TRACE_MEMORY_REGION_OPS_READ_ENABLED) { hwaddr abs_addr = memory_region_to_absolute_addr(mr, addr); trace_memory_region_ops_read(get_cpu_index(), mr, abs_addr, tmp, size); @@ -486,11 +476,6 @@ static MemTxResult memory_region_write_accessor(MemoryRegion *mr, if (mr->subpage) { trace_memory_region_subpage_write(get_cpu_index(), mr, addr, tmp, size); - } else if (mr == &io_mem_notdirty) { - /* Accesses to code which has previously been translated into a TB show - * up in the MMIO path, as accesses to the io_mem_notdirty - * MemoryRegion. */ - trace_memory_region_tb_write(get_cpu_index(), addr, tmp, size); } else if (TRACE_MEMORY_REGION_OPS_WRITE_ENABLED) { hwaddr abs_addr = memory_region_to_absolute_addr(mr, addr); trace_memory_region_ops_write(get_cpu_index(), mr, abs_addr, tmp, size); @@ -511,11 +496,6 @@ static MemTxResult memory_region_write_with_attrs_accessor(MemoryRegion *mr, if (mr->subpage) { trace_memory_region_subpage_write(get_cpu_index(), mr, addr, tmp, size); - } else if (mr == &io_mem_notdirty) { - /* Accesses to code which has previously been translated into a TB show - * up in the MMIO path, as accesses to the io_mem_notdirty - * MemoryRegion. */ - trace_memory_region_tb_write(get_cpu_index(), addr, tmp, size); } else if (TRACE_MEMORY_REGION_OPS_WRITE_ENABLED) { hwaddr abs_addr = memory_region_to_absolute_addr(mr, addr); trace_memory_region_ops_write(get_cpu_index(), mr, abs_addr, tmp, size); @@ -1837,33 +1817,38 @@ bool memory_region_is_logging(MemoryRegion *mr, uint8_t client) return memory_region_get_dirty_log_mask(mr) & (1 << client); } -static void memory_region_update_iommu_notify_flags(IOMMUMemoryRegion *iommu_mr) +static int memory_region_update_iommu_notify_flags(IOMMUMemoryRegion *iommu_mr, + Error **errp) { IOMMUNotifierFlag flags = IOMMU_NOTIFIER_NONE; IOMMUNotifier *iommu_notifier; IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr); + int ret = 0; IOMMU_NOTIFIER_FOREACH(iommu_notifier, iommu_mr) { flags |= iommu_notifier->notifier_flags; } if (flags != iommu_mr->iommu_notify_flags && imrc->notify_flag_changed) { - imrc->notify_flag_changed(iommu_mr, - iommu_mr->iommu_notify_flags, - flags); + ret = imrc->notify_flag_changed(iommu_mr, + iommu_mr->iommu_notify_flags, + flags, errp); } - iommu_mr->iommu_notify_flags = flags; + if (!ret) { + iommu_mr->iommu_notify_flags = flags; + } + return ret; } -void memory_region_register_iommu_notifier(MemoryRegion *mr, - IOMMUNotifier *n) +int memory_region_register_iommu_notifier(MemoryRegion *mr, + IOMMUNotifier *n, Error **errp) { IOMMUMemoryRegion *iommu_mr; + int ret; if (mr->alias) { - memory_region_register_iommu_notifier(mr->alias, n); - return; + return memory_region_register_iommu_notifier(mr->alias, n, errp); } /* We need to register for at least one bitfield */ @@ -1874,7 +1859,11 @@ void memory_region_register_iommu_notifier(MemoryRegion *mr, n->iommu_idx < memory_region_iommu_num_indexes(iommu_mr)); QLIST_INSERT_HEAD(&iommu_mr->iommu_notify, n, node); - memory_region_update_iommu_notify_flags(iommu_mr); + ret = memory_region_update_iommu_notify_flags(iommu_mr, errp); + if (ret) { + QLIST_REMOVE(n, node); + } + return ret; } uint64_t memory_region_iommu_get_min_page_size(IOMMUMemoryRegion *iommu_mr) @@ -1927,7 +1916,7 @@ void memory_region_unregister_iommu_notifier(MemoryRegion *mr, } QLIST_REMOVE(n, node); iommu_mr = IOMMU_MEMORY_REGION(mr); - memory_region_update_iommu_notify_flags(iommu_mr); + memory_region_update_iommu_notify_flags(iommu_mr, NULL); } void memory_region_notify_one(IOMMUNotifier *notifier, diff --git a/migration/migration.c b/migration/migration.c index 01863a95f5..5f7e4d15e9 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1659,7 +1659,14 @@ bool migration_in_postcopy(void) { MigrationState *s = migrate_get_current(); - return (s->state == MIGRATION_STATUS_POSTCOPY_ACTIVE); + switch (s->state) { + case MIGRATION_STATUS_POSTCOPY_ACTIVE: + case MIGRATION_STATUS_POSTCOPY_PAUSED: + case MIGRATION_STATUS_POSTCOPY_RECOVER: + return true; + default: + return false; + } } bool migration_in_postcopy_after_devices(MigrationState *s) diff --git a/migration/qjson.h b/migration/qjson.h index 41664f2d71..1786bb5864 100644 --- a/migration/qjson.h +++ b/migration/qjson.h @@ -24,4 +24,6 @@ void json_start_object(QJSON *json, const char *name); const char *qjson_get_str(QJSON *json); void qjson_finish(QJSON *json); +G_DEFINE_AUTOPTR_CLEANUP_FUNC(QJSON, qjson_destroy) + #endif /* QEMU_QJSON_H */ diff --git a/migration/ram.c b/migration/ram.c index 01df326767..22423f08cd 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -2348,7 +2348,7 @@ static bool get_queued_page(RAMState *rs, PageSearchStatus *pss) dirty = test_bit(page, block->bmap); if (!dirty) { trace_get_queued_page_not_dirty(block->idstr, (uint64_t)offset, - page, test_bit(page, block->unsentmap)); + page); } else { trace_get_queued_page(block->idstr, (uint64_t)offset, page); } @@ -2619,10 +2619,6 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss, } pages += tmppages; - if (pss->block->unsentmap) { - clear_bit(pss->page, pss->block->unsentmap); - } - pss->page++; } while ((pss->page & (pagesize_bits - 1)) && offset_in_ramblock(pss->block, pss->page << TARGET_PAGE_BITS)); @@ -2776,8 +2772,6 @@ static void ram_save_cleanup(void *opaque) block->clear_bmap = NULL; g_free(block->bmap); block->bmap = NULL; - g_free(block->unsentmap); - block->unsentmap = NULL; } xbzrle_cleanup(); @@ -2857,8 +2851,6 @@ void ram_postcopy_migrated_memory_release(MigrationState *ms) * Returns zero on success * * Callback from postcopy_each_ram_send_discard for each RAMBlock - * Note: At this point the 'unsentmap' is the processed bitmap combined - * with the dirtymap; so a '1' means it's either dirty or unsent. * * @ms: current migration state * @block: RAMBlock to discard @@ -2867,17 +2859,17 @@ static int postcopy_send_discard_bm_ram(MigrationState *ms, RAMBlock *block) { unsigned long end = block->used_length >> TARGET_PAGE_BITS; unsigned long current; - unsigned long *unsentmap = block->unsentmap; + unsigned long *bitmap = block->bmap; for (current = 0; current < end; ) { - unsigned long one = find_next_bit(unsentmap, end, current); + unsigned long one = find_next_bit(bitmap, end, current); unsigned long zero, discard_length; if (one >= end) { break; } - zero = find_next_zero_bit(unsentmap, end, one + 1); + zero = find_next_zero_bit(bitmap, end, one + 1); if (zero >= end) { discard_length = end - one; @@ -2928,7 +2920,7 @@ static int postcopy_each_ram_send_discard(MigrationState *ms) } /** - * postcopy_chunk_hostpages_pass: canocalize bitmap in hostpages + * postcopy_chunk_hostpages_pass: canonicalize bitmap in hostpages * * Helper for postcopy_chunk_hostpages; it's called twice to * canonicalize the two bitmaps, that are similar, but one is @@ -2938,16 +2930,12 @@ static int postcopy_each_ram_send_discard(MigrationState *ms) * clean, not a mix. This function canonicalizes the bitmaps. * * @ms: current migration state - * @unsent_pass: if true we need to canonicalize partially unsent host pages - * otherwise we need to canonicalize partially dirty host pages * @block: block that contains the page we want to canonicalize */ -static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass, - RAMBlock *block) +static void postcopy_chunk_hostpages_pass(MigrationState *ms, RAMBlock *block) { RAMState *rs = ram_state; unsigned long *bitmap = block->bmap; - unsigned long *unsentmap = block->unsentmap; unsigned int host_ratio = block->page_size / TARGET_PAGE_SIZE; unsigned long pages = block->used_length >> TARGET_PAGE_BITS; unsigned long run_start; @@ -2957,13 +2945,8 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass, return; } - if (unsent_pass) { - /* Find a sent page */ - run_start = find_next_zero_bit(unsentmap, pages, 0); - } else { - /* Find a dirty page */ - run_start = find_next_bit(bitmap, pages, 0); - } + /* Find a dirty page */ + run_start = find_next_bit(bitmap, pages, 0); while (run_start < pages) { @@ -2973,11 +2956,7 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass, */ if (QEMU_IS_ALIGNED(run_start, host_ratio)) { /* Find the end of this run */ - if (unsent_pass) { - run_start = find_next_bit(unsentmap, pages, run_start + 1); - } else { - run_start = find_next_zero_bit(bitmap, pages, run_start + 1); - } + run_start = find_next_zero_bit(bitmap, pages, run_start + 1); /* * If the end isn't at the start of a host page, then the * run doesn't finish at the end of a host page @@ -2991,24 +2970,9 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass, host_ratio); run_start = QEMU_ALIGN_UP(run_start, host_ratio); - /* Tell the destination to discard this page */ - if (unsent_pass || !test_bit(fixup_start_addr, unsentmap)) { - /* For the unsent_pass we: - * discard partially sent pages - * For the !unsent_pass (dirty) we: - * discard partially dirty pages that were sent - * (any partially sent pages were already discarded - * by the previous unsent_pass) - */ - postcopy_discard_send_range(ms, fixup_start_addr, host_ratio); - } - /* Clean up the bitmap */ for (page = fixup_start_addr; page < fixup_start_addr + host_ratio; page++) { - /* All pages in this host page are now not sent */ - set_bit(page, unsentmap); - /* * Remark them as dirty, updating the count for any pages * that weren't previously dirty. @@ -3017,13 +2981,8 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass, } } - if (unsent_pass) { - /* Find the next sent page for the next iteration */ - run_start = find_next_zero_bit(unsentmap, pages, run_start); - } else { - /* Find the next dirty page for the next iteration */ - run_start = find_next_bit(bitmap, pages, run_start); - } + /* Find the next dirty page for the next iteration */ + run_start = find_next_bit(bitmap, pages, run_start); } } @@ -3045,13 +3004,10 @@ static int postcopy_chunk_hostpages(MigrationState *ms, RAMBlock *block) { postcopy_discard_send_init(ms, block->idstr); - /* First pass: Discard all partially sent host pages */ - postcopy_chunk_hostpages_pass(ms, true, block); /* - * Second pass: Ensure that all partially dirty host pages are made - * fully dirty. + * Ensure that all partially dirty host pages are made fully dirty. */ - postcopy_chunk_hostpages_pass(ms, false, block); + postcopy_chunk_hostpages_pass(ms, block); postcopy_discard_send_finish(ms); return 0; @@ -3089,19 +3045,6 @@ int ram_postcopy_send_discard_bitmap(MigrationState *ms) rs->last_page = 0; RAMBLOCK_FOREACH_NOT_IGNORED(block) { - unsigned long pages = block->used_length >> TARGET_PAGE_BITS; - unsigned long *bitmap = block->bmap; - unsigned long *unsentmap = block->unsentmap; - - if (!unsentmap) { - /* We don't have a safe way to resize the sentmap, so - * if the bitmap was resized it will be NULL at this - * point. - */ - error_report("migration ram resized during precopy phase"); - rcu_read_unlock(); - return -EINVAL; - } /* Deal with TPS != HPS and huge pages */ ret = postcopy_chunk_hostpages(ms, block); if (ret) { @@ -3109,12 +3052,9 @@ int ram_postcopy_send_discard_bitmap(MigrationState *ms) return ret; } - /* - * Update the unsentmap to be unsentmap = unsentmap | dirty - */ - bitmap_or(unsentmap, unsentmap, bitmap, pages); #ifdef DEBUG_POSTCOPY - ram_debug_dump_bitmap(unsentmap, true, pages); + ram_debug_dump_bitmap(block->bmap, true, + block->used_length >> TARGET_PAGE_BITS); #endif } trace_ram_postcopy_send_discard_bitmap(); @@ -3282,10 +3222,6 @@ static void ram_list_init_bitmaps(void) bitmap_set(block->bmap, 0, pages); block->clear_bmap_shift = shift; block->clear_bmap = bitmap_new(clear_bmap_size(pages, shift)); - if (migrate_postcopy_ram()) { - block->unsentmap = bitmap_new(pages); - bitmap_set(block->unsentmap, 0, pages); - } } } } diff --git a/migration/rdma.c b/migration/rdma.c index 78e6b72bac..4c74e88a37 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -3017,11 +3017,35 @@ static void qio_channel_rdma_set_aio_fd_handler(QIOChannel *ioc, } } +struct rdma_close_rcu { + struct rcu_head rcu; + RDMAContext *rdmain; + RDMAContext *rdmaout; +}; + +/* callback from qio_channel_rdma_close via call_rcu */ +static void qio_channel_rdma_close_rcu(struct rdma_close_rcu *rcu) +{ + if (rcu->rdmain) { + qemu_rdma_cleanup(rcu->rdmain); + } + + if (rcu->rdmaout) { + qemu_rdma_cleanup(rcu->rdmaout); + } + + g_free(rcu->rdmain); + g_free(rcu->rdmaout); + g_free(rcu); +} + static int qio_channel_rdma_close(QIOChannel *ioc, Error **errp) { QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(ioc); RDMAContext *rdmain, *rdmaout; + struct rdma_close_rcu *rcu = g_new(struct rdma_close_rcu, 1); + trace_qemu_rdma_close(); rdmain = rioc->rdmain; @@ -3034,18 +3058,9 @@ static int qio_channel_rdma_close(QIOChannel *ioc, atomic_rcu_set(&rioc->rdmaout, NULL); } - synchronize_rcu(); - - if (rdmain) { - qemu_rdma_cleanup(rdmain); - } - - if (rdmaout) { - qemu_rdma_cleanup(rdmaout); - } - - g_free(rdmain); - g_free(rdmaout); + rcu->rdmain = rdmain; + rcu->rdmaout = rdmaout; + call_rcu(rcu, qio_channel_rdma_close_rcu, rcu); return 0; } @@ -3253,10 +3268,14 @@ static void rdma_cm_poll_handler(void *opaque) if (cm_event->event == RDMA_CM_EVENT_DISCONNECTED || cm_event->event == RDMA_CM_EVENT_DEVICE_REMOVAL) { - error_report("receive cm event, cm event is %d", cm_event->event); - rdma->error_state = -EPIPE; - if (rdma->return_path) { - rdma->return_path->error_state = -EPIPE; + if (!rdma->error_state && + migration_incoming_get_current()->state != + MIGRATION_STATUS_COMPLETED) { + error_report("receive cm event, cm event is %d", cm_event->event); + rdma->error_state = -EPIPE; + if (rdma->return_path) { + rdma->return_path->error_state = -EPIPE; + } } if (mis->migration_incoming_co) { diff --git a/migration/savevm.c b/migration/savevm.c index ee06f91d42..bb9462a54d 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -1314,7 +1314,7 @@ int qemu_savevm_state_complete_precopy_non_iterable(QEMUFile *f, bool in_postcopy, bool inactivate_disks) { - QJSON *vmdesc; + g_autoptr(QJSON) vmdesc = NULL; int vmdesc_len; SaveStateEntry *se; int ret; @@ -1375,7 +1375,6 @@ int qemu_savevm_state_complete_precopy_non_iterable(QEMUFile *f, qemu_put_be32(f, vmdesc_len); qemu_put_buffer(f, (uint8_t *)qjson_get_str(vmdesc), vmdesc_len); } - qjson_destroy(vmdesc); return 0; } diff --git a/migration/trace-events b/migration/trace-events index 00ffcd5930..858d415d56 100644 --- a/migration/trace-events +++ b/migration/trace-events @@ -76,7 +76,7 @@ qemu_file_fclose(void) "" # ram.c get_queued_page(const char *block_name, uint64_t tmp_offset, unsigned long page_abs) "%s/0x%" PRIx64 " page_abs=0x%lx" -get_queued_page_not_dirty(const char *block_name, uint64_t tmp_offset, unsigned long page_abs, int sent) "%s/0x%" PRIx64 " page_abs=0x%lx (sent=%d)" +get_queued_page_not_dirty(const char *block_name, uint64_t tmp_offset, unsigned long page_abs) "%s/0x%" PRIx64 " page_abs=0x%lx" migration_bitmap_sync_start(void) "" migration_bitmap_sync_end(uint64_t dirty_pages) "dirty_pages %" PRIu64 migration_bitmap_clear_dirty(char *str, uint64_t start, uint64_t size, unsigned long page) "rb %s start 0x%"PRIx64" size 0x%"PRIx64" page 0x%lx" diff --git a/nbd/client.c b/nbd/client.c index b9dc829175..f6733962b4 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -204,6 +204,7 @@ static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply, case NBD_REP_ERR_TLS_REQD: error_setg(errp, "TLS negotiation required before option %" PRIu32 " (%s)", reply->option, nbd_opt_lookup(reply->option)); + error_append_hint(errp, "Did you forget a valid tls-creds?\n"); break; case NBD_REP_ERR_UNKNOWN: diff --git a/nbd/server.c b/nbd/server.c index 28c3c8be85..d8d1e62455 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -1297,6 +1297,11 @@ static coroutine_fn int nbd_negotiate(NBDClient *client, Error **errp) return ret; } + /* Attach the channel to the same AioContext as the export */ + if (client->exp && client->exp->ctx) { + qio_channel_attach_aio_context(client->ioc, client->exp->ctx); + } + assert(!client->optlen); trace_nbd_negotiate_success(); @@ -1456,7 +1461,12 @@ static void blk_aio_detach(void *opaque) static void nbd_eject_notifier(Notifier *n, void *data) { NBDExport *exp = container_of(n, NBDExport, eject_notifier); + AioContext *aio_context; + + aio_context = exp->ctx; + aio_context_acquire(aio_context); nbd_export_close(exp); + aio_context_release(aio_context); } NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, @@ -1475,12 +1485,11 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, * NBD exports are used for non-shared storage migration. Make sure * that BDRV_O_INACTIVE is cleared and the image is ready for write * access since the export could be available before migration handover. + * ctx was acquired in the caller. */ assert(name); ctx = bdrv_get_aio_context(bs); - aio_context_acquire(ctx); bdrv_invalidate_cache(bs, NULL); - aio_context_release(ctx); /* Don't allow resize while the NBD server is running, otherwise we don't * care what happens with the node. */ @@ -1488,7 +1497,7 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, if (!readonly) { perm |= BLK_PERM_WRITE; } - blk = blk_new(bdrv_get_aio_context(bs), perm, + blk = blk_new(ctx, perm, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE | BLK_PERM_GRAPH_MOD); ret = blk_insert_bs(blk, bs, errp); @@ -1555,7 +1564,7 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, } exp->close = close; - exp->ctx = blk_get_aio_context(blk); + exp->ctx = ctx; blk_add_aio_context_notifier(blk, blk_aio_attached, blk_aio_detach, exp); if (on_eject_blk) { @@ -1588,6 +1597,12 @@ NBDExport *nbd_export_find(const char *name) return NULL; } +AioContext * +nbd_export_aio_context(NBDExport *exp) +{ + return exp->ctx; +} + void nbd_export_close(NBDExport *exp) { NBDClient *client, *next; @@ -1682,9 +1697,13 @@ BlockBackend *nbd_export_get_blockdev(NBDExport *exp) void nbd_export_close_all(void) { NBDExport *exp, *next; + AioContext *aio_context; QTAILQ_FOREACH_SAFE(exp, &exports, next, next) { + aio_context = exp->ctx; + aio_context_acquire(aio_context); nbd_export_close(exp); + aio_context_release(aio_context); } } diff --git a/pc-bios/README b/pc-bios/README index ad78f6dc49..0b0b5d42ad 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -17,7 +17,7 @@ - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware implementation for certain IBM POWER hardware. The sources are at https://github.com/aik/SLOF, and the image currently in qemu is - built from git tag qemu-slof-20190827. + built from git tag qemu-slof-20190911. - sgabios (the Serial Graphics Adapter option ROM) provides a means for legacy x86 software to communicate with an attached serial console as diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin Binary files differindex a3a3e49332..2af0c5d5fc 100644 --- a/pc-bios/slof.bin +++ b/pc-bios/slof.bin diff --git a/pc-bios/spapr-rtas.bin b/pc-bios/spapr-rtas.bin Binary files differdeleted file mode 100644 index fc24c8ed8b..0000000000 --- a/pc-bios/spapr-rtas.bin +++ /dev/null diff --git a/pc-bios/spapr-rtas/Makefile b/pc-bios/spapr-rtas/Makefile deleted file mode 100644 index 4b9bb12306..0000000000 --- a/pc-bios/spapr-rtas/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -all: build-all -# Dummy command so that make thinks it has done something - @true - -include ../../config-host.mak -include $(SRC_PATH)/rules.mak - -$(call set-vpath, $(SRC_PATH)/pc-bios/spapr-rtas) - -.PHONY : all clean build-all - -#CFLAGS += -I$(SRC_PATH) -#QEMU_CFLAGS = $(CFLAGS) - -build-all: spapr-rtas.bin - -%.o: %.S - $(call quiet-command,$(CCAS) -mbig -c -o $@ $<,"CCAS","$(TARGET_DIR)$@") - -%.img: %.o - $(call quiet-command,$(CC) -nostdlib -mbig -o $@ $<,"Building","$(TARGET_DIR)$@") - -%.bin: %.img - $(call quiet-command,$(OBJCOPY) -O binary -j .text $< $@,"Building","$(TARGET_DIR)$@") - -clean: - rm -f *.o *.d *.img *.bin *~ diff --git a/pc-bios/spapr-rtas/spapr-rtas.S b/pc-bios/spapr-rtas/spapr-rtas.S deleted file mode 100644 index 903bec2150..0000000000 --- a/pc-bios/spapr-rtas/spapr-rtas.S +++ /dev/null @@ -1,37 +0,0 @@ -/* - * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator - * - * Trivial in-partition RTAS implementation, based on a hypercall - * - * Copyright (c) 2010,2011 David Gibson, IBM Corporation. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -#define KVMPPC_HCALL_BASE 0xf000 -#define KVMPPC_H_RTAS (KVMPPC_HCALL_BASE + 0x0) - -.globl _start -_start: - mr 4,3 - lis 3,KVMPPC_H_RTAS@h - ori 3,3,KVMPPC_H_RTAS@l - sc 1 - blr diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c index 324b197495..5fe0276c1c 100644 --- a/qapi/opts-visitor.c +++ b/qapi/opts-visitor.c @@ -24,7 +24,8 @@ enum ListMode { LM_NONE, /* not traversing a list of repeated options */ - LM_IN_PROGRESS, /* opts_next_list() ready to be called. + LM_IN_PROGRESS, /* + * opts_next_list() ready to be called. * * Generating the next list link will consume the most * recently parsed QemuOpt instance of the repeated @@ -36,7 +37,8 @@ enum ListMode * LM_UNSIGNED_INTERVAL. */ - LM_SIGNED_INTERVAL, /* opts_next_list() has been called. + LM_SIGNED_INTERVAL, /* + * opts_next_list() has been called. * * Generating the next list link will consume the most * recently stored element from the signed interval, @@ -48,7 +50,14 @@ enum ListMode * next element of the signed interval. */ - LM_UNSIGNED_INTERVAL /* Same as above, only for an unsigned interval. */ + LM_UNSIGNED_INTERVAL, /* Same as above, only for an unsigned interval. */ + + LM_TRAVERSED /* + * opts_next_list() has been called. + * + * No more QemuOpt instance in the list. + * The traversal has been completed. + */ }; typedef enum ListMode ListMode; @@ -238,6 +247,8 @@ opts_next_list(Visitor *v, GenericList *tail, size_t size) OptsVisitor *ov = to_ov(v); switch (ov->list_mode) { + case LM_TRAVERSED: + return NULL; case LM_SIGNED_INTERVAL: case LM_UNSIGNED_INTERVAL: if (ov->list_mode == LM_SIGNED_INTERVAL) { @@ -258,6 +269,8 @@ opts_next_list(Visitor *v, GenericList *tail, size_t size) opt = g_queue_pop_head(ov->repeated_opts); if (g_queue_is_empty(ov->repeated_opts)) { g_hash_table_remove(ov->unprocessed_opts, opt->name); + ov->repeated_opts = NULL; + ov->list_mode = LM_TRAVERSED; return NULL; } break; @@ -289,7 +302,8 @@ opts_end_list(Visitor *v, void **obj) assert(ov->list_mode == LM_IN_PROGRESS || ov->list_mode == LM_SIGNED_INTERVAL || - ov->list_mode == LM_UNSIGNED_INTERVAL); + ov->list_mode == LM_UNSIGNED_INTERVAL || + ov->list_mode == LM_TRAVERSED); ov->repeated_opts = NULL; ov->list_mode = LM_NONE; } @@ -306,6 +320,10 @@ lookup_scalar(const OptsVisitor *ov, const char *name, Error **errp) list = lookup_distinct(ov, name, errp); return list ? g_queue_peek_tail(list) : NULL; } + if (ov->list_mode == LM_TRAVERSED) { + error_setg(errp, "Fewer list elements than expected"); + return NULL; + } assert(ov->list_mode == LM_IN_PROGRESS); return g_queue_peek_head(ov->repeated_opts); } diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json index 920b03b0aa..9751b11f8f 100644 --- a/qapi/qapi-schema.json +++ b/qapi/qapi-schema.json @@ -71,7 +71,7 @@ 'QapiErrorClass', # all members, visible through errors 'UuidInfo', # UUID, visible through query-uuid 'X86CPURegister32', # all members, visible indirectly through qom-get - 'q_obj_CpuInfo-base' # CPU, visible through query-cpu + 'CpuInfo' # CPU, visible through query-cpu ] } } # Documentation generated with qapi-gen.py is in source order, with diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c index 3037d353a4..bc264b3c9b 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c @@ -104,8 +104,9 @@ static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request, return NULL; } if (!cmd->enabled) { - error_setg(errp, "The command %s has been disabled for this instance", - command); + error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND, + "The command %s has been disabled for this instance", + command); return NULL; } if (oob && !(cmd->options & QCO_ALLOW_OOB)) { diff --git a/roms/SLOF b/roms/SLOF -Subproject ea221600a116883137ef90b2b7ab7d2472bc4f1 +Subproject bcc3c4e5c21a015f4680894c4ec978a90d4a2d6 diff --git a/scripts/git.orderfile b/scripts/git.orderfile index ac699700b1..e89790941c 100644 --- a/scripts/git.orderfile +++ b/scripts/git.orderfile @@ -19,11 +19,11 @@ Makefile* *.mak # qapi schema -*.json +qapi/*.json +qga/*.json # headers *.h # code *.c - diff --git a/scripts/kvm/vmxcap b/scripts/kvm/vmxcap index d8c7d6dfb8..5dfeb2e03a 100755 --- a/scripts/kvm/vmxcap +++ b/scripts/kvm/vmxcap @@ -51,15 +51,15 @@ class Control(object): return (val & 0xffffffff, val >> 32) def show(self): print(self.name) - mbz, mb1 = self.read2(self.cap_msr) - tmbz, tmb1 = 0, 0 + mb1, cb1 = self.read2(self.cap_msr) + tmb1, tcb1 = 0, 0 if self.true_cap_msr: - tmbz, tmb1 = self.read2(self.true_cap_msr) + tmb1, tcb1 = self.read2(self.true_cap_msr) for bit in sorted(self.bits.keys()): - zero = not (mbz & (1 << bit)) - one = mb1 & (1 << bit) - true_zero = not (tmbz & (1 << bit)) - true_one = tmb1 & (1 << bit) + zero = not (mb1 & (1 << bit)) + one = cb1 & (1 << bit) + true_zero = not (tmb1 & (1 << bit)) + true_one = tcb1 & (1 << bit) s= '?' if (self.true_cap_msr and true_zero and true_one and one and not zero): diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py index b929e07be4..7e3dd1068a 100644 --- a/scripts/qapi/commands.py +++ b/scripts/qapi/commands.py @@ -30,7 +30,7 @@ def gen_call(name, arg_type, boxed, ret_type): argstr = '' if boxed: - assert arg_type and not arg_type.is_empty() + assert arg_type argstr = '&arg, ' elif arg_type: assert not arg_type.variants @@ -96,7 +96,7 @@ def gen_marshal_decl(name): def gen_marshal(name, arg_type, boxed, ret_type): - have_args = arg_type and not arg_type.is_empty() + have_args = boxed or (arg_type and not arg_type.is_empty()) ret = mcgen(''' diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index d61bfdc526..d6e00c80ea 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -13,6 +13,7 @@ from __future__ import print_function from contextlib import contextmanager +import copy import errno import os import re @@ -20,25 +21,6 @@ import string import sys from collections import OrderedDict -builtin_types = { - 'null': 'QTYPE_QNULL', - 'str': 'QTYPE_QSTRING', - 'int': 'QTYPE_QNUM', - 'number': 'QTYPE_QNUM', - 'bool': 'QTYPE_QBOOL', - 'int8': 'QTYPE_QNUM', - 'int16': 'QTYPE_QNUM', - 'int32': 'QTYPE_QNUM', - 'int64': 'QTYPE_QNUM', - 'uint8': 'QTYPE_QNUM', - 'uint16': 'QTYPE_QNUM', - 'uint32': 'QTYPE_QNUM', - 'uint64': 'QTYPE_QNUM', - 'size': 'QTYPE_QNUM', - 'any': None, # any QType possible, actually - 'QType': 'QTYPE_QSTRING', -} - # Are documentation comments required? doc_required = False @@ -48,39 +30,67 @@ returns_whitelist = [] # Whitelist of entities allowed to violate case conventions name_case_whitelist = [] -enum_types = {} -struct_types = {} -union_types = {} -all_names = {} # # Parsing the schema into expressions # +class QAPISourceInfo(object): + def __init__(self, fname, line, parent): + self.fname = fname + self.line = line + self.parent = parent + self.defn_meta = None + self.defn_name = None + + def set_defn(self, meta, name): + self.defn_meta = meta + self.defn_name = name + + def next_line(self): + info = copy.copy(self) + info.line += 1 + return info + + def loc(self): + if self.fname is None: + return sys.argv[0] + ret = self.fname + if self.line is not None: + ret += ':%d' % self.line + return ret + + def in_defn(self): + if self.defn_name: + return "%s: In %s '%s':\n" % (self.fname, + self.defn_meta, self.defn_name) + return '' + + def include_path(self): + ret = '' + parent = self.parent + while parent: + ret = 'In file included from %s:\n' % parent.loc() + ret + parent = parent.parent + return ret -def error_path(parent): - res = '' - while parent: - res = ('In file included from %s:%d:\n' % (parent['file'], - parent['line'])) + res - parent = parent['parent'] - return res + def __str__(self): + return self.include_path() + self.in_defn() + self.loc() class QAPIError(Exception): - def __init__(self, fname, line, col, incl_info, msg): + def __init__(self, info, col, msg): Exception.__init__(self) - self.fname = fname - self.line = line + self.info = info self.col = col - self.info = incl_info self.msg = msg def __str__(self): - loc = '%s:%d' % (self.fname, self.line) + loc = str(self.info) if self.col is not None: + assert self.info.line is not None loc += ':%s' % self.col - return error_path(self.info) + '%s: %s' % (loc, self.msg) + return loc + ': ' + self.msg class QAPIParseError(QAPIError): @@ -91,23 +101,21 @@ class QAPIParseError(QAPIError): col = (col + 7) % 8 + 1 else: col += 1 - QAPIError.__init__(self, parser.fname, parser.line, col, - parser.incl_info, msg) + QAPIError.__init__(self, parser.info, col, msg) class QAPISemError(QAPIError): def __init__(self, info, msg): - QAPIError.__init__(self, info['file'], info['line'], None, - info['parent'], msg) + QAPIError.__init__(self, info, None, msg) class QAPIDoc(object): """ - A documentation comment block, either expression or free-form + A documentation comment block, either definition or free-form - Expression documentation blocks consist of + Definition documentation blocks consist of - * a body section: one line naming the expression, followed by an + * a body section: one line naming the definition, followed by an overview (any number of lines) * argument sections: a description of each argument (for commands @@ -180,7 +188,7 @@ class QAPIDoc(object): return if line[0] != ' ': - raise QAPIParseError(self._parser, "Missing space after #") + raise QAPIParseError(self._parser, "missing space after #") line = line[1:] self._append_line(line) @@ -200,9 +208,9 @@ class QAPIDoc(object): Process a line of documentation text in the body section. If this a symbol line and it is the section's first line, this - is an expression documentation block for that symbol. + is a definition documentation block for that symbol. - If it's an expression documentation block, another symbol line + If it's a definition documentation block, another symbol line begins the argument section for the argument named by it, and a section tag begins an additional section. Start that section and append the line to it. @@ -214,13 +222,13 @@ class QAPIDoc(object): # recognized, and get silently treated as ordinary text if not self.symbol and not self.body.text and line.startswith('@'): if not line.endswith(':'): - raise QAPIParseError(self._parser, "Line should end with :") + raise QAPIParseError(self._parser, "line should end with ':'") self.symbol = line[1:-1] # FIXME invalid names other than the empty string aren't flagged if not self.symbol: - raise QAPIParseError(self._parser, "Invalid name") + raise QAPIParseError(self._parser, "invalid name") elif self.symbol: - # This is an expression documentation block + # This is a definition documentation block if name.startswith('@') and name.endswith(':'): self._append_line = self._append_args_line self._append_args_line(line) @@ -317,7 +325,7 @@ class QAPIDoc(object): def _start_symbol_section(self, symbols_dict, name): # FIXME invalid names other than the empty string aren't flagged if not name: - raise QAPIParseError(self._parser, "Invalid parameter name") + raise QAPIParseError(self._parser, "invalid parameter name") if name in symbols_dict: raise QAPIParseError(self._parser, "'%s' parameter name duplicated" % name) @@ -335,7 +343,7 @@ class QAPIDoc(object): def _start_section(self, name=None): if name in ('Returns', 'Since') and self.has_section(name): raise QAPIParseError(self._parser, - "Duplicated '%s' section" % name) + "duplicated '%s' section" % name) self._end_section() self._section = QAPIDoc.Section(name) self.sections.append(self._section) @@ -344,8 +352,9 @@ class QAPIDoc(object): if self._section: text = self._section.text = self._section.text.strip() if self._section.name and (not text or text.isspace()): - raise QAPIParseError(self._parser, "Empty doc section '%s'" - % self._section.name) + raise QAPIParseError( + self._parser, + "empty doc section '%s'" % self._section.name) self._section = None def _append_freeform(self, line): @@ -373,21 +382,32 @@ class QAPIDoc(object): if bogus: raise QAPISemError( self.info, - "The following documented members are not in " + "the following documented members are not in " "the declaration: %s" % ", ".join(bogus)) class QAPISchemaParser(object): - def __init__(self, fp, previously_included=[], incl_info=None): - self.fname = fp.name - previously_included.append(os.path.abspath(fp.name)) - self.incl_info = incl_info - self.src = fp.read() + def __init__(self, fname, previously_included=[], incl_info=None): + previously_included.append(os.path.abspath(fname)) + + try: + if sys.version_info[0] >= 3: + fp = open(fname, 'r', encoding='utf-8') + else: + fp = open(fname, 'r') + self.src = fp.read() + except IOError as e: + raise QAPISemError(incl_info or QAPISourceInfo(None, None, None), + "can't read %s file '%s': %s" + % ("include" if incl_info else "schema", + fname, + e.strerror)) + if self.src == '' or self.src[-1] != '\n': self.src += '\n' self.cursor = 0 - self.line = 1 + self.info = QAPISourceInfo(fname, 1, incl_info) self.line_pos = 0 self.exprs = [] self.docs = [] @@ -395,8 +415,7 @@ class QAPISchemaParser(object): cur_doc = None while self.tok is not None: - info = {'file': self.fname, 'line': self.line, - 'parent': self.incl_info} + info = self.info if self.tok == '#': self.reject_expr_doc(cur_doc) cur_doc = self.get_doc(info) @@ -407,12 +426,12 @@ class QAPISchemaParser(object): if 'include' in expr: self.reject_expr_doc(cur_doc) if len(expr) != 1: - raise QAPISemError(info, "Invalid 'include' directive") + raise QAPISemError(info, "invalid 'include' directive") include = expr['include'] if not isinstance(include, str): raise QAPISemError(info, - "Value of 'include' must be a string") - incl_fname = os.path.join(os.path.dirname(self.fname), + "value of 'include' must be a string") + incl_fname = os.path.join(os.path.dirname(fname), include) self.exprs.append({'expr': {'include': incl_fname}, 'info': info}) @@ -424,11 +443,11 @@ class QAPISchemaParser(object): elif "pragma" in expr: self.reject_expr_doc(cur_doc) if len(expr) != 1: - raise QAPISemError(info, "Invalid 'pragma' directive") + raise QAPISemError(info, "invalid 'pragma' directive") pragma = expr['pragma'] if not isinstance(pragma, dict): raise QAPISemError( - info, "Value of 'pragma' must be a dictionary") + info, "value of 'pragma' must be an object") for name, value in pragma.items(): self._pragma(name, value, info) else: @@ -437,7 +456,7 @@ class QAPISchemaParser(object): if cur_doc: if not cur_doc.symbol: raise QAPISemError( - cur_doc.info, "Expression documentation required") + cur_doc.info, "definition documentation required") expr_elem['doc'] = cur_doc self.exprs.append(expr_elem) cur_doc = None @@ -448,7 +467,7 @@ class QAPISchemaParser(object): if doc and doc.symbol: raise QAPISemError( doc.info, - "Documentation for '%s' is not followed by the definition" + "documentation for '%s' is not followed by the definition" % doc.symbol) def _include(self, include, info, incl_fname, previously_included): @@ -456,46 +475,39 @@ class QAPISchemaParser(object): # catch inclusion cycle inf = info while inf: - if incl_abs_fname == os.path.abspath(inf['file']): - raise QAPISemError(info, "Inclusion loop for %s" % include) - inf = inf['parent'] + if incl_abs_fname == os.path.abspath(inf.fname): + raise QAPISemError(info, "inclusion loop for %s" % include) + inf = inf.parent # skip multiple include of the same file if incl_abs_fname in previously_included: return None - try: - if sys.version_info[0] >= 3: - fobj = open(incl_fname, 'r', encoding='utf-8') - else: - fobj = open(incl_fname, 'r') - except IOError as e: - raise QAPISemError(info, '%s: %s' % (e.strerror, incl_fname)) - return QAPISchemaParser(fobj, previously_included, info) + return QAPISchemaParser(incl_fname, previously_included, info) def _pragma(self, name, value, info): global doc_required, returns_whitelist, name_case_whitelist if name == 'doc-required': if not isinstance(value, bool): raise QAPISemError(info, - "Pragma 'doc-required' must be boolean") + "pragma 'doc-required' must be boolean") doc_required = value elif name == 'returns-whitelist': if (not isinstance(value, list) or any([not isinstance(elt, str) for elt in value])): - raise QAPISemError(info, - "Pragma returns-whitelist must be" - " a list of strings") + raise QAPISemError( + info, + "pragma returns-whitelist must be a list of strings") returns_whitelist = value elif name == 'name-case-whitelist': if (not isinstance(value, list) or any([not isinstance(elt, str) for elt in value])): - raise QAPISemError(info, - "Pragma name-case-whitelist must be" - " a list of strings") + raise QAPISemError( + info, + "pragma name-case-whitelist must be a list of strings") name_case_whitelist = value else: - raise QAPISemError(info, "Unknown pragma '%s'" % name) + raise QAPISemError(info, "unknown pragma '%s'" % name) def accept(self, skip_comment=True): while True: @@ -515,57 +527,31 @@ class QAPISchemaParser(object): elif self.tok in '{}:,[]': return elif self.tok == "'": + # Note: we accept only printable ASCII string = '' esc = False while True: ch = self.src[self.cursor] self.cursor += 1 if ch == '\n': - raise QAPIParseError(self, 'Missing terminating "\'"') + raise QAPIParseError(self, "missing terminating \"'\"") if esc: - if ch == 'b': - string += '\b' - elif ch == 'f': - string += '\f' - elif ch == 'n': - string += '\n' - elif ch == 'r': - string += '\r' - elif ch == 't': - string += '\t' - elif ch == 'u': - value = 0 - for _ in range(0, 4): - ch = self.src[self.cursor] - self.cursor += 1 - if ch not in '0123456789abcdefABCDEF': - raise QAPIParseError(self, - '\\u escape needs 4 ' - 'hex digits') - value = (value << 4) + int(ch, 16) - # If Python 2 and 3 didn't disagree so much on - # how to handle Unicode, then we could allow - # Unicode string defaults. But most of QAPI is - # ASCII-only, so we aren't losing much for now. - if not value or value > 0x7f: - raise QAPIParseError(self, - 'For now, \\u escape ' - 'only supports non-zero ' - 'values up to \\u007f') - string += chr(value) - elif ch in '\\/\'"': - string += ch - else: + # Note: we recognize only \\ because we have + # no use for funny characters in strings + if ch != '\\': raise QAPIParseError(self, - "Unknown escape \\%s" % ch) + "unknown escape \\%s" % ch) esc = False elif ch == '\\': esc = True + continue elif ch == "'": self.val = string return - else: - string += ch + if ord(ch) < 32 or ord(ch) >= 127: + raise QAPIParseError( + self, "funny character in string") + string += ch elif self.src.startswith('true', self.pos): self.val = True self.cursor += 3 @@ -574,18 +560,18 @@ class QAPISchemaParser(object): self.val = False self.cursor += 4 return - elif self.src.startswith('null', self.pos): - self.val = None - self.cursor += 3 - return elif self.tok == '\n': if self.cursor == len(self.src): self.tok = None return - self.line += 1 + self.info = self.info.next_line() self.line_pos = self.cursor elif not self.tok.isspace(): - raise QAPIParseError(self, 'Stray "%s"' % self.tok) + # Show up to next structural, whitespace or quote + # character + match = re.match('[^[\\]{}:,\\s\'"]+', + self.src[self.cursor-1:]) + raise QAPIParseError(self, "stray '%s'" % match.group(0)) def get_members(self): expr = OrderedDict() @@ -593,24 +579,24 @@ class QAPISchemaParser(object): self.accept() return expr if self.tok != "'": - raise QAPIParseError(self, 'Expected string or "}"') + raise QAPIParseError(self, "expected string or '}'") while True: key = self.val self.accept() if self.tok != ':': - raise QAPIParseError(self, 'Expected ":"') + raise QAPIParseError(self, "expected ':'") self.accept() if key in expr: - raise QAPIParseError(self, 'Duplicate key "%s"' % key) + raise QAPIParseError(self, "duplicate key '%s'" % key) expr[key] = self.get_expr(True) if self.tok == '}': self.accept() return expr if self.tok != ',': - raise QAPIParseError(self, 'Expected "," or "}"') + raise QAPIParseError(self, "expected ',' or '}'") self.accept() if self.tok != "'": - raise QAPIParseError(self, 'Expected string') + raise QAPIParseError(self, "expected string") def get_values(self): expr = [] @@ -618,20 +604,20 @@ class QAPISchemaParser(object): self.accept() return expr if self.tok not in "{['tfn": - raise QAPIParseError(self, 'Expected "{", "[", "]", string, ' - 'boolean or "null"') + raise QAPIParseError( + self, "expected '{', '[', ']', string, boolean or 'null'") while True: expr.append(self.get_expr(True)) if self.tok == ']': self.accept() return expr if self.tok != ',': - raise QAPIParseError(self, 'Expected "," or "]"') + raise QAPIParseError(self, "expected ',' or ']'") self.accept() def get_expr(self, nested): if self.tok != '{' and not nested: - raise QAPIParseError(self, 'Expected "{"') + raise QAPIParseError(self, "expected '{'") if self.tok == '{': self.accept() expr = self.get_members() @@ -642,14 +628,14 @@ class QAPISchemaParser(object): expr = self.val self.accept() else: - raise QAPIParseError(self, 'Expected "{", "[", string, ' - 'boolean or "null"') + raise QAPIParseError( + self, "expected '{', '[', string, boolean or 'null'") return expr def get_doc(self, info): if self.val != '##': - raise QAPIParseError(self, "Junk after '##' at start of " - "documentation comment") + raise QAPIParseError( + self, "junk after '##' at start of documentation comment") doc = QAPIDoc(self, info) self.accept(False) @@ -657,8 +643,9 @@ class QAPISchemaParser(object): if self.val.startswith('##'): # End of doc comment if self.val != '##': - raise QAPIParseError(self, "Junk after '##' at end of " - "documentation comment") + raise QAPIParseError( + self, + "junk after '##' at end of documentation comment") doc.end_comment() self.accept() return doc @@ -666,58 +653,13 @@ class QAPISchemaParser(object): doc.append(self.val) self.accept(False) - raise QAPIParseError(self, "Documentation comment must end with '##'") + raise QAPIParseError(self, "documentation comment must end with '##'") # -# Semantic analysis of schema expressions -# TODO fold into QAPISchema -# TODO catching name collisions in generated code would be nice +# Check (context-free) schema expression structure # - -def find_base_members(base): - if isinstance(base, dict): - return base - base_struct_define = struct_types.get(base) - if not base_struct_define: - return None - return base_struct_define['data'] - - -# Return the qtype of an alternate branch, or None on error. -def find_alternate_member_qtype(qapi_type): - if qapi_type in builtin_types: - return builtin_types[qapi_type] - elif qapi_type in struct_types: - return 'QTYPE_QDICT' - elif qapi_type in enum_types: - return 'QTYPE_QSTRING' - elif qapi_type in union_types: - return 'QTYPE_QDICT' - return None - - -# Return the discriminator enum define if discriminator is specified as an -# enum type, otherwise return None. -def discriminator_find_enum_define(expr): - base = expr.get('base') - discriminator = expr.get('discriminator') - - if not (discriminator and base): - return None - - base_members = find_base_members(base) - if not base_members: - return None - - discriminator_value = base_members.get(discriminator) - if not discriminator_value: - return None - - return enum_types.get(discriminator_value['type']) - - # Names must be letters, numbers, -, and _. They must start with letter, # except for downstream extensions which must start with __RFQDN_. # Dots are only valid in the downstream extension prefix. @@ -725,18 +667,19 @@ valid_name = re.compile(r'^(__[a-zA-Z0-9.-]+_)?' '[a-zA-Z][a-zA-Z0-9_-]*$') -def check_name(info, source, name, allow_optional=False, - enum_member=False): +def check_name_is_str(name, info, source): + if not isinstance(name, str): + raise QAPISemError(info, "%s requires a string name" % source) + + +def check_name_str(name, info, source, + allow_optional=False, enum_member=False, + permit_upper=False): global valid_name membername = name - if not isinstance(name, str): - raise QAPISemError(info, "%s requires a string name" % source) - if name.startswith('*'): + if allow_optional and name.startswith('*'): membername = name[1:] - if not allow_optional: - raise QAPISemError(info, "%s does not allow optional name '%s'" - % (source, name)) # Enum members can start with a digit, because the generated C # code always prefixes it with the enum name if enum_member and membername[0].isdigit(): @@ -745,53 +688,53 @@ def check_name(info, source, name, allow_optional=False, # and 'q_obj_*' implicit type names. if not valid_name.match(membername) or \ c_name(membername, False).startswith('q_'): - raise QAPISemError(info, "%s uses invalid name '%s'" % (source, name)) + raise QAPISemError(info, "%s has an invalid name" % source) + if not permit_upper and name.lower() != name: + raise QAPISemError( + info, "%s uses uppercase in name" % source) + assert not membername.startswith('*') -def add_name(name, info, meta, implicit=False): - global all_names - check_name(info, "'%s'" % meta, name) - # FIXME should reject names that differ only in '_' vs. '.' - # vs. '-', because they're liable to clash in generated C. - if name in all_names: - raise QAPISemError(info, "%s '%s' is already defined" - % (all_names[name], name)) - if not implicit and (name.endswith('Kind') or name.endswith('List')): - raise QAPISemError(info, "%s '%s' should not end in '%s'" - % (meta, name, name[-4:])) - all_names[name] = meta +def check_defn_name_str(name, info, meta): + check_name_str(name, info, meta, permit_upper=True) + if name.endswith('Kind') or name.endswith('List'): + raise QAPISemError( + info, "%s name should not end in '%s'" % (meta, name[-4:])) -def check_if(expr, info): +def check_if(expr, info, source): def check_if_str(ifcond, info): if not isinstance(ifcond, str): raise QAPISemError( - info, "'if' condition must be a string or a list of strings") - if ifcond == '': - raise QAPISemError(info, "'if' condition '' makes no sense") + info, + "'if' condition of %s must be a string or a list of strings" + % source) + if ifcond.strip() == '': + raise QAPISemError( + info, + "'if' condition '%s' of %s makes no sense" + % (ifcond, source)) ifcond = expr.get('if') if ifcond is None: return if isinstance(ifcond, list): if ifcond == []: - raise QAPISemError(info, "'if' condition [] is useless") + raise QAPISemError( + info, "'if' condition [] of %s is useless" % source) for elt in ifcond: check_if_str(elt, info) else: check_if_str(ifcond, info) -def check_type(info, source, value, allow_array=False, - allow_dict=False, allow_optional=False, - allow_metas=[]): - global all_names - +def check_type(value, info, source, + allow_array=False, allow_dict=False): if value is None: return - # Check if array type for value is okay + # Array type if isinstance(value, list): if not allow_array: raise QAPISemError(info, "%s cannot be an array" % source) @@ -799,74 +742,54 @@ def check_type(info, source, value, allow_array=False, raise QAPISemError(info, "%s: array type must contain single type name" % source) - value = value[0] + return - # Check if type name for value is okay + # Type name if isinstance(value, str): - if value not in all_names: - raise QAPISemError(info, "%s uses unknown type '%s'" - % (source, value)) - if not all_names[value] in allow_metas: - raise QAPISemError(info, "%s cannot use %s type '%s'" % - (source, all_names[value], value)) return + # Anonymous type + if not allow_dict: raise QAPISemError(info, "%s should be a type name" % source) if not isinstance(value, OrderedDict): raise QAPISemError(info, - "%s should be a dictionary or type name" % source) + "%s should be an object or type name" % source) + + permit_upper = allow_dict in name_case_whitelist # value is a dictionary, check that each member is okay for (key, arg) in value.items(): - check_name(info, "Member of %s" % source, key, - allow_optional=allow_optional) + key_source = "%s member '%s'" % (source, key) + check_name_str(key, info, key_source, + allow_optional=True, permit_upper=permit_upper) if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'): - raise QAPISemError(info, "Member of %s uses reserved name '%s'" - % (source, key)) - # Todo: allow dictionaries to represent default values of - # an optional argument. - check_known_keys(info, "member '%s' of %s" % (key, source), - arg, ['type'], ['if']) - check_type(info, "Member '%s' of %s" % (key, source), - arg['type'], allow_array=True, - allow_metas=['built-in', 'union', 'alternate', 'struct', - 'enum']) + raise QAPISemError(info, "%s uses reserved name" % key_source) + check_keys(arg, info, key_source, ['type'], ['if']) + check_if(arg, info, key_source) + normalize_if(arg) + check_type(arg['type'], info, key_source, allow_array=True) def check_command(expr, info): - name = expr['command'] + args = expr.get('data') + rets = expr.get('returns') boxed = expr.get('boxed', False) - args_meta = ['struct'] - if boxed: - args_meta += ['union', 'alternate'] - check_type(info, "'data' for command '%s'" % name, - expr.get('data'), allow_dict=not boxed, allow_optional=True, - allow_metas=args_meta) - returns_meta = ['union', 'struct'] - if name in returns_whitelist: - returns_meta += ['built-in', 'alternate', 'enum'] - check_type(info, "'returns' for command '%s'" % name, - expr.get('returns'), allow_array=True, - allow_optional=True, allow_metas=returns_meta) + if boxed and args is None: + raise QAPISemError(info, "'boxed': true requires 'data'") + check_type(args, info, "'data'", allow_dict=not boxed) + check_type(rets, info, "'returns'", allow_array=True) def check_event(expr, info): - name = expr['event'] + args = expr.get('data') boxed = expr.get('boxed', False) - meta = ['struct'] - if boxed: - meta += ['union', 'alternate'] - check_type(info, "'data' for event '%s'" % name, - expr.get('data'), allow_dict=not boxed, allow_optional=True, - allow_metas=meta) - - -def enum_get_names(expr): - return [e['name'] for e in expr['data']] + if boxed and args is None: + raise QAPISemError(info, "'boxed': true requires 'data'") + check_type(args, info, "'data'", allow_dict=not boxed) def check_union(expr, info): @@ -875,115 +798,36 @@ def check_union(expr, info): discriminator = expr.get('discriminator') members = expr['data'] - # Two types of unions, determined by discriminator. - - # With no discriminator it is a simple union. - if discriminator is None: - enum_define = None - allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum'] + if discriminator is None: # simple union if base is not None: - raise QAPISemError(info, "Simple union '%s' must not have a base" % - name) - - # Else, it's a flat union. - else: - # The object must have a string or dictionary 'base'. - check_type(info, "'base' for union '%s'" % name, - base, allow_dict=True, allow_optional=True, - allow_metas=['struct']) + raise QAPISemError(info, "'base' requires 'discriminator'") + else: # flat union + check_type(base, info, "'base'", allow_dict=name) if not base: - raise QAPISemError(info, "Flat union '%s' must have a base" - % name) - base_members = find_base_members(base) - assert base_members is not None - - # The value of member 'discriminator' must name a non-optional - # member of the base struct. - check_name(info, "Discriminator of flat union '%s'" % name, - discriminator) - discriminator_value = base_members.get(discriminator) - if not discriminator_value: - raise QAPISemError(info, - "Discriminator '%s' is not a member of base " - "struct '%s'" - % (discriminator, base)) - if discriminator_value.get('if'): - raise QAPISemError(info, 'The discriminator %s.%s for union %s ' - 'must not be conditional' % - (base, discriminator, name)) - enum_define = enum_types.get(discriminator_value['type']) - allow_metas = ['struct'] - # Do not allow string discriminator - if not enum_define: - raise QAPISemError(info, - "Discriminator '%s' must be of enumeration " - "type" % discriminator) + raise QAPISemError(info, "'discriminator' requires 'base'") + check_name_is_str(discriminator, info, "'discriminator'") - # Check every branch; don't allow an empty union - if len(members) == 0: - raise QAPISemError(info, "Union '%s' cannot have empty 'data'" % name) for (key, value) in members.items(): - check_name(info, "Member of union '%s'" % name, key) - - check_known_keys(info, "member '%s' of union '%s'" % (key, name), - value, ['type'], ['if']) - # Each value must name a known type - check_type(info, "Member '%s' of union '%s'" % (key, name), - value['type'], - allow_array=not base, allow_metas=allow_metas) - - # If the discriminator names an enum type, then all members - # of 'data' must also be members of the enum type. - if enum_define: - if key not in enum_get_names(enum_define): - raise QAPISemError(info, - "Discriminator value '%s' is not found in " - "enum '%s'" - % (key, enum_define['enum'])) + source = "'data' member '%s'" % key + check_name_str(key, info, source) + check_keys(value, info, source, ['type'], ['if']) + check_if(value, info, source) + normalize_if(value) + check_type(value['type'], info, source, allow_array=not base) def check_alternate(expr, info): - name = expr['alternate'] members = expr['data'] - types_seen = {} - # Check every branch; require at least two branches - if len(members) < 2: - raise QAPISemError(info, - "Alternate '%s' should have at least two branches " - "in 'data'" % name) + if len(members) == 0: + raise QAPISemError(info, "'data' must not be empty") for (key, value) in members.items(): - check_name(info, "Member of alternate '%s'" % name, key) - check_known_keys(info, - "member '%s' of alternate '%s'" % (key, name), - value, ['type'], ['if']) - typ = value['type'] - - # Ensure alternates have no type conflicts. - check_type(info, "Member '%s' of alternate '%s'" % (key, name), typ, - allow_metas=['built-in', 'union', 'struct', 'enum']) - qtype = find_alternate_member_qtype(typ) - if not qtype: - raise QAPISemError(info, "Alternate '%s' member '%s' cannot use " - "type '%s'" % (name, key, typ)) - conflicting = set([qtype]) - if qtype == 'QTYPE_QSTRING': - enum_expr = enum_types.get(typ) - if enum_expr: - for v in enum_get_names(enum_expr): - if v in ['on', 'off']: - conflicting.add('QTYPE_QBOOL') - if re.match(r'[-+0-9.]', v): # lazy, could be tightened - conflicting.add('QTYPE_QNUM') - else: - conflicting.add('QTYPE_QNUM') - conflicting.add('QTYPE_QBOOL') - for qt in conflicting: - if qt in types_seen: - raise QAPISemError(info, "Alternate '%s' member '%s' can't " - "be distinguished from member '%s'" - % (name, key, types_seen[qt])) - types_seen[qt] = key + source = "'data' member '%s'" % key + check_name_str(key, info, source) + check_keys(value, info, source, ['type'], ['if']) + check_if(value, info, source) + normalize_if(value) + check_type(value['type'], info, source) def check_enum(expr, info): @@ -992,18 +836,21 @@ def check_enum(expr, info): prefix = expr.get('prefix') if not isinstance(members, list): - raise QAPISemError(info, - "Enum '%s' requires an array for 'data'" % name) + raise QAPISemError(info, "'data' must be an array") if prefix is not None and not isinstance(prefix, str): - raise QAPISemError(info, - "Enum '%s' requires a string for 'prefix'" % name) + raise QAPISemError(info, "'prefix' must be a string") + + permit_upper = name in name_case_whitelist for member in members: - source = "dictionary member of enum '%s'" % name - check_known_keys(info, source, member, ['name'], ['if']) - check_if(member, info) - check_name(info, "Member of enum '%s'" % name, member['name'], - enum_member=True) + source = "'data' member" + check_keys(member, info, source, ['name'], ['if']) + check_name_is_str(member['name'], info, source) + source = "%s '%s'" % (source, member['name']) + check_name_str(member['name'], info, source, + enum_member=True, permit_upper=permit_upper) + check_if(member, info, source) + normalize_if(member) def check_struct(expr, info): @@ -1011,64 +858,54 @@ def check_struct(expr, info): members = expr['data'] features = expr.get('features') - check_type(info, "'data' for struct '%s'" % name, members, - allow_dict=True, allow_optional=True) - check_type(info, "'base' for struct '%s'" % name, expr.get('base'), - allow_metas=['struct']) + check_type(members, info, "'data'", allow_dict=name) + check_type(expr.get('base'), info, "'base'") if features: if not isinstance(features, list): - raise QAPISemError(info, - "Struct '%s' requires an array for 'features'" % - name) + raise QAPISemError(info, "'features' must be an array") for f in features: + source = "'features' member" assert isinstance(f, dict) - check_known_keys(info, "feature of struct %s" % name, f, - ['name'], ['if']) - - check_if(f, info) - check_name(info, "Feature of struct %s" % name, f['name']) + check_keys(f, info, source, ['name'], ['if']) + check_name_is_str(f['name'], info, source) + source = "%s '%s'" % (source, f['name']) + check_name_str(f['name'], info, source) + check_if(f, info, source) + normalize_if(f) -def check_known_keys(info, source, keys, required, optional): +def check_keys(value, info, source, required, optional): def pprint(elems): return ', '.join("'" + e + "'" for e in sorted(elems)) - missing = set(required) - set(keys) + missing = set(required) - set(value) if missing: - raise QAPISemError(info, "Key%s %s %s missing from %s" - % ('s' if len(missing) > 1 else '', pprint(missing), - 'are' if len(missing) > 1 else 'is', source)) + raise QAPISemError( + info, + "%s misses key%s %s" + % (source, 's' if len(missing) > 1 else '', + pprint(missing))) allowed = set(required + optional) - unknown = set(keys) - allowed + unknown = set(value) - allowed if unknown: - raise QAPISemError(info, "Unknown key%s %s in %s\nValid keys are %s." - % ('s' if len(unknown) > 1 else '', pprint(unknown), - source, pprint(allowed))) + raise QAPISemError( + info, + "%s has unknown key%s %s\nValid keys are %s." + % (source, 's' if len(unknown) > 1 else '', + pprint(unknown), pprint(allowed))) -def check_keys(expr_elem, meta, required, optional=[]): - expr = expr_elem['expr'] - info = expr_elem['info'] - name = expr[meta] - if not isinstance(name, str): - raise QAPISemError(info, "'%s' key must have a string value" % meta) - required = required + [meta] - source = "%s '%s'" % (meta, name) - check_known_keys(info, source, expr.keys(), required, optional) - for (key, value) in expr.items(): - if key in ['gen', 'success-response'] and value is not False: - raise QAPISemError(info, - "'%s' of %s '%s' should only use false value" - % (key, meta, name)) - if (key in ['boxed', 'allow-oob', 'allow-preconfig'] - and value is not True): - raise QAPISemError(info, - "'%s' of %s '%s' should only use true value" - % (key, meta, name)) - if key == 'if': - check_if(expr, info) +def check_flags(expr, info): + for key in ['gen', 'success-response']: + if key in expr and expr[key] is not False: + raise QAPISemError( + info, "flag '%s' may only use false value" % key) + for key in ['boxed', 'allow-oob', 'allow-preconfig']: + if key in expr and expr[key] is not True: + raise QAPISemError( + info, "flag '%s' may only use true value" % key) def normalize_enum(expr): @@ -1091,14 +928,13 @@ def normalize_features(features): for f in features] -def check_exprs(exprs): - global all_names +def normalize_if(expr): + ifcond = expr.get('if') + if isinstance(ifcond, str): + expr['if'] = [ifcond] - # Populate name table with names of built-in types - for builtin in builtin_types.keys(): - all_names[builtin] = 'built-in' - # Learn the types and check for valid expression keys +def check_exprs(exprs): for expr_elem in exprs: expr = expr_elem['expr'] info = expr_elem['info'] @@ -1107,113 +943,93 @@ def check_exprs(exprs): if 'include' in expr: continue - if not doc and doc_required: - raise QAPISemError(info, - "Expression missing documentation comment") - if 'enum' in expr: meta = 'enum' - check_keys(expr_elem, 'enum', ['data'], ['if', 'prefix']) - normalize_enum(expr) - enum_types[expr[meta]] = expr elif 'union' in expr: meta = 'union' - check_keys(expr_elem, 'union', ['data'], - ['base', 'discriminator', 'if']) - normalize_members(expr.get('base')) - normalize_members(expr['data']) - union_types[expr[meta]] = expr elif 'alternate' in expr: meta = 'alternate' - check_keys(expr_elem, 'alternate', ['data'], ['if']) - normalize_members(expr['data']) elif 'struct' in expr: meta = 'struct' - check_keys(expr_elem, 'struct', ['data'], - ['base', 'if', 'features']) - normalize_members(expr['data']) - normalize_features(expr.get('features')) - struct_types[expr[meta]] = expr elif 'command' in expr: meta = 'command' - check_keys(expr_elem, 'command', [], - ['data', 'returns', 'gen', 'success-response', - 'boxed', 'allow-oob', 'allow-preconfig', 'if']) - normalize_members(expr.get('data')) elif 'event' in expr: meta = 'event' - check_keys(expr_elem, 'event', [], ['data', 'boxed', 'if']) - normalize_members(expr.get('data')) else: - raise QAPISemError(expr_elem['info'], - "Expression is missing metatype") - name = expr[meta] - add_name(name, info, meta) - if doc and doc.symbol != name: - raise QAPISemError(info, "Definition of '%s' follows documentation" - " for '%s'" % (name, doc.symbol)) + raise QAPISemError(info, "expression is missing metatype") - # Try again for hidden UnionKind enum - for expr_elem in exprs: - expr = expr_elem['expr'] - - if 'include' in expr: - continue - if 'union' in expr and not discriminator_find_enum_define(expr): - name = '%sKind' % expr['union'] - elif 'alternate' in expr: - name = '%sKind' % expr['alternate'] - else: - continue - enum_types[name] = {'enum': name} - add_name(name, info, 'enum', implicit=True) + name = expr[meta] + check_name_is_str(name, info, "'%s'" % meta) + info.set_defn(meta, name) + check_defn_name_str(name, info, meta) - # Validate that exprs make sense - for expr_elem in exprs: - expr = expr_elem['expr'] - info = expr_elem['info'] - doc = expr_elem.get('doc') + if doc: + if doc.symbol != name: + raise QAPISemError( + info, "documentation comment is for '%s'" % doc.symbol) + doc.check_expr(expr) + elif doc_required: + raise QAPISemError(info, + "documentation comment required") - if 'include' in expr: - continue - if 'enum' in expr: + if meta == 'enum': + check_keys(expr, info, meta, + ['enum', 'data'], ['if', 'prefix']) + normalize_enum(expr) check_enum(expr, info) - elif 'union' in expr: + elif meta == 'union': + check_keys(expr, info, meta, + ['union', 'data'], + ['base', 'discriminator', 'if']) + normalize_members(expr.get('base')) + normalize_members(expr['data']) check_union(expr, info) - elif 'alternate' in expr: + elif meta == 'alternate': + check_keys(expr, info, meta, + ['alternate', 'data'], ['if']) + normalize_members(expr['data']) check_alternate(expr, info) - elif 'struct' in expr: + elif meta == 'struct': + check_keys(expr, info, meta, + ['struct', 'data'], ['base', 'if', 'features']) + normalize_members(expr['data']) + normalize_features(expr.get('features')) check_struct(expr, info) - elif 'command' in expr: + elif meta == 'command': + check_keys(expr, info, meta, + ['command'], + ['data', 'returns', 'boxed', 'if', + 'gen', 'success-response', 'allow-oob', + 'allow-preconfig']) + normalize_members(expr.get('data')) check_command(expr, info) - elif 'event' in expr: + elif meta == 'event': + check_keys(expr, info, meta, + ['event'], ['data', 'boxed', 'if']) + normalize_members(expr.get('data')) check_event(expr, info) else: assert False, 'unexpected meta type' - if doc: - doc.check_expr(expr) + normalize_if(expr) + check_if(expr, info, meta) + check_flags(expr, info) return exprs # # Schema compiler frontend +# TODO catching name collisions in generated code would be nice # -def listify_cond(ifcond): - if not ifcond: - return [] - if not isinstance(ifcond, list): - return [ifcond] - return ifcond - - class QAPISchemaEntity(object): + meta = None + def __init__(self, name, info, doc, ifcond=None): assert name is None or isinstance(name, str) self.name = name - self.module = None + self._module = None # For explicitly defined entities, info points to the (explicit) # definition. For builtins (and their arrays), info is None. # For implicitly defined entities, info points to a place that @@ -1221,28 +1037,38 @@ class QAPISchemaEntity(object): # such place). self.info = info self.doc = doc - self._ifcond = ifcond # self.ifcond is set only after .check() + self._ifcond = ifcond or [] + self._checked = False def c_name(self): return c_name(self.name) def check(self, schema): - if isinstance(self._ifcond, QAPISchemaType): - # inherit the condition from a type - typ = self._ifcond - typ.check(schema) - self.ifcond = typ.ifcond - else: - self.ifcond = listify_cond(self._ifcond) + assert not self._checked if self.info: - self.module = os.path.relpath(self.info['file'], - os.path.dirname(schema.fname)) + self._module = os.path.relpath(self.info.fname, + os.path.dirname(schema.fname)) + self._checked = True + + @property + def ifcond(self): + assert self._checked + return self._ifcond + + @property + def module(self): + assert self._checked + return self._module def is_implicit(self): return not self.info def visit(self, visitor): - pass + assert self._checked + + def describe(self): + assert self.meta + return "%s '%s'" % (self.meta, self.name) class QAPISchemaVisitor(object): @@ -1297,6 +1123,7 @@ class QAPISchemaInclude(QAPISchemaEntity): self.fname = fname def visit(self, visitor): + QAPISchemaEntity.visit(self, visitor) visitor.visit_include(self.fname, self.info) @@ -1333,8 +1160,14 @@ class QAPISchemaType(QAPISchemaEntity): return None return self.name + def describe(self): + assert self.meta + return "%s type '%s'" % (self.meta, self.name) + class QAPISchemaBuiltinType(QAPISchemaType): + meta = 'built-in' + def __init__(self, name, json_type, c_type): QAPISchemaType.__init__(self, name, None, None) assert not c_type or isinstance(c_type, str) @@ -1361,15 +1194,18 @@ class QAPISchemaBuiltinType(QAPISchemaType): return self.json_type() def visit(self, visitor): + QAPISchemaType.visit(self, visitor) visitor.visit_builtin_type(self.name, self.info, self.json_type()) class QAPISchemaEnumType(QAPISchemaType): + meta = 'enum' + def __init__(self, name, info, doc, ifcond, members, prefix): QAPISchemaType.__init__(self, name, info, doc, ifcond) for m in members: - assert isinstance(m, QAPISchemaMember) - m.set_owner(name) + assert isinstance(m, QAPISchemaEnumMember) + m.set_defined_in(name) assert prefix is None or isinstance(prefix, str) self.members = members self.prefix = prefix @@ -1396,11 +1232,14 @@ class QAPISchemaEnumType(QAPISchemaType): return 'string' def visit(self, visitor): + QAPISchemaType.visit(self, visitor) visitor.visit_enum_type(self.name, self.info, self.ifcond, self.members, self.prefix) class QAPISchemaArrayType(QAPISchemaType): + meta = 'array' + def __init__(self, name, info, element_type): QAPISchemaType.__init__(self, name, info, None, None) assert isinstance(element_type, str) @@ -1409,11 +1248,20 @@ class QAPISchemaArrayType(QAPISchemaType): def check(self, schema): QAPISchemaType.check(self, schema) - self.element_type = schema.lookup_type(self._element_type_name) - assert self.element_type - self.element_type.check(schema) - self.module = self.element_type.module - self.ifcond = self.element_type.ifcond + self.element_type = schema.resolve_type( + self._element_type_name, self.info, + self.info and self.info.defn_meta) + assert not isinstance(self.element_type, QAPISchemaArrayType) + + @property + def ifcond(self): + assert self._checked + return self.element_type.ifcond + + @property + def module(self): + assert self._checked + return self.element_type.module def is_implicit(self): return True @@ -1431,9 +1279,14 @@ class QAPISchemaArrayType(QAPISchemaType): return 'array of ' + elt_doc_type def visit(self, visitor): + QAPISchemaType.visit(self, visitor) visitor.visit_array_type(self.name, self.info, self.ifcond, self.element_type) + def describe(self): + assert self.meta + return "%s type ['%s']" % (self.meta, self._element_type_name) + class QAPISchemaObjectType(QAPISchemaType): def __init__(self, name, info, doc, ifcond, @@ -1442,16 +1295,17 @@ class QAPISchemaObjectType(QAPISchemaType): # flat union has base, variants, and no local_members # simple union has local_members, variants, and no base QAPISchemaType.__init__(self, name, info, doc, ifcond) + self.meta = 'union' if variants else 'struct' assert base is None or isinstance(base, str) for m in local_members: assert isinstance(m, QAPISchemaObjectTypeMember) - m.set_owner(name) + m.set_defined_in(name) if variants is not None: assert isinstance(variants, QAPISchemaObjectTypeVariants) - variants.set_owner(name) + variants.set_defined_in(name) for f in features: assert isinstance(f, QAPISchemaFeature) - f.set_owner(name) + f.set_defined_in(name) self._base_name = base self.base = None self.local_members = local_members @@ -1460,17 +1314,30 @@ class QAPISchemaObjectType(QAPISchemaType): self.features = features def check(self, schema): - QAPISchemaType.check(self, schema) - if self.members is False: # check for cycles - raise QAPISemError(self.info, - "Object %s contains itself" % self.name) - if self.members: + # This calls another type T's .check() exactly when the C + # struct emitted by gen_object() contains that T's C struct + # (pointers don't count). + if self.members is not None: + # A previous .check() completed: nothing to do return - self.members = False # mark as being checked + if self._checked: + # Recursed: C struct contains itself + raise QAPISemError(self.info, + "object %s contains itself" % self.name) + + QAPISchemaType.check(self, schema) + assert self._checked and self.members is None + seen = OrderedDict() if self._base_name: - self.base = schema.lookup_type(self._base_name) - assert isinstance(self.base, QAPISchemaObjectType) + self.base = schema.resolve_type(self._base_name, self.info, + "'base'") + if (not isinstance(self.base, QAPISchemaObjectType) + or self.base.variants): + raise QAPISemError( + self.info, + "'base' requires a struct type, %s isn't" + % self.base.describe()) self.base.check(schema) self.base.check_clash(self.info, seen) for m in self.local_members: @@ -1478,10 +1345,10 @@ class QAPISchemaObjectType(QAPISchemaType): m.check_clash(self.info, seen) if self.doc: self.doc.connect_member(m) - self.members = seen.values() + members = seen.values() + if self.variants: self.variants.check(schema, seen) - assert self.variants.tag_member in self.members self.variants.check_clash(self.info, seen) # Features are in a name space separate from members @@ -1492,14 +1359,26 @@ class QAPISchemaObjectType(QAPISchemaType): if self.doc: self.doc.check() + self.members = members # mark completed + # Check that the members of this type do not cause duplicate JSON members, # and update seen to track the members seen so far. Report any errors # on behalf of info, which is not necessarily self.info def check_clash(self, info, seen): + assert self._checked assert not self.variants # not implemented for m in self.members: m.check_clash(info, seen) + @property + def ifcond(self): + assert self._checked + if isinstance(self._ifcond, QAPISchemaType): + # Simple union wrapper type inherits from wrapped type; + # see _make_implicit_object_type() + return self._ifcond.ifcond + return self._ifcond + def is_implicit(self): # See QAPISchema._make_implicit_object_type(), as well as # _def_predefineds() @@ -1524,6 +1403,7 @@ class QAPISchemaObjectType(QAPISchemaType): return 'object' def visit(self, visitor): + QAPISchemaType.visit(self, visitor) visitor.visit_object_type(self.name, self.info, self.ifcond, self.base, self.local_members, self.variants, self.features) @@ -1536,47 +1416,59 @@ class QAPISchemaMember(object): """ Represents object members, enum members and features """ role = 'member' - def __init__(self, name, ifcond=None): + def __init__(self, name, info, ifcond=None): assert isinstance(name, str) self.name = name - self.ifcond = listify_cond(ifcond) - self.owner = None + self.info = info + self.ifcond = ifcond or [] + self.defined_in = None - def set_owner(self, name): - assert not self.owner - self.owner = name + def set_defined_in(self, name): + assert not self.defined_in + self.defined_in = name def check_clash(self, info, seen): cname = c_name(self.name) - if cname.lower() != cname and self.owner not in name_case_whitelist: - raise QAPISemError(info, - "%s should not use uppercase" % self.describe()) if cname in seen: - raise QAPISemError(info, "%s collides with %s" % - (self.describe(), seen[cname].describe())) + raise QAPISemError( + info, + "%s collides with %s" + % (self.describe(info), seen[cname].describe(info))) seen[cname] = self - def _pretty_owner(self): - owner = self.owner - if owner.startswith('q_obj_'): + def describe(self, info): + role = self.role + defined_in = self.defined_in + assert defined_in + + if defined_in.startswith('q_obj_'): # See QAPISchema._make_implicit_object_type() - reverse the # mapping there to create a nice human-readable description - owner = owner[6:] - if owner.endswith('-arg'): - return '(parameter of %s)' % owner[:-4] - elif owner.endswith('-base'): - return '(base of %s)' % owner[:-5] + defined_in = defined_in[6:] + if defined_in.endswith('-arg'): + # Implicit type created for a command's dict 'data' + assert role == 'member' + role = 'parameter' + elif defined_in.endswith('-base'): + # Implicit type created for a flat union's dict 'base' + role = 'base ' + role else: - assert owner.endswith('-wrapper') + # Implicit type created for a simple union's branch + assert defined_in.endswith('-wrapper') # Unreachable and not implemented assert False - if owner.endswith('Kind'): + elif defined_in.endswith('Kind'): # See QAPISchema._make_implicit_enum_type() - return '(branch of %s)' % owner[:-4] - return '(%s of %s)' % (self.role, owner) + # Implicit enum created for simple union's branches + assert role == 'value' + role = 'branch' + elif defined_in != info.defn_name: + return "%s '%s' of type '%s'" % (role, self.name, defined_in) + return "%s '%s'" % (role, self.name) - def describe(self): - return "'%s' %s" % (self.name, self._pretty_owner()) + +class QAPISchemaEnumMember(QAPISchemaMember): + role = 'value' class QAPISchemaFeature(QAPISchemaMember): @@ -1584,8 +1476,8 @@ class QAPISchemaFeature(QAPISchemaMember): class QAPISchemaObjectTypeMember(QAPISchemaMember): - def __init__(self, name, typ, optional, ifcond=None): - QAPISchemaMember.__init__(self, name, ifcond) + def __init__(self, name, info, typ, optional, ifcond=None): + QAPISchemaMember.__init__(self, name, info, ifcond) assert isinstance(typ, str) assert isinstance(optional, bool) self._type_name = typ @@ -1593,13 +1485,13 @@ class QAPISchemaObjectTypeMember(QAPISchemaMember): self.optional = optional def check(self, schema): - assert self.owner - self.type = schema.lookup_type(self._type_name) - assert self.type + assert self.defined_in + self.type = schema.resolve_type(self._type_name, self.info, + self.describe) class QAPISchemaObjectTypeVariants(object): - def __init__(self, tag_name, tag_member, variants): + def __init__(self, tag_name, info, tag_member, variants): # Flat unions pass tag_name but not tag_member. # Simple unions and alternates pass tag_member but not tag_name. # After check(), tag_member is always set, and tag_name remains @@ -1607,62 +1499,105 @@ class QAPISchemaObjectTypeVariants(object): assert bool(tag_member) != bool(tag_name) assert (isinstance(tag_name, str) or isinstance(tag_member, QAPISchemaObjectTypeMember)) - assert len(variants) > 0 for v in variants: assert isinstance(v, QAPISchemaObjectTypeVariant) self._tag_name = tag_name + self.info = info self.tag_member = tag_member self.variants = variants - def set_owner(self, name): + def set_defined_in(self, name): for v in self.variants: - v.set_owner(name) + v.set_defined_in(name) def check(self, schema, seen): - if not self.tag_member: # flat union - self.tag_member = seen[c_name(self._tag_name)] - assert self._tag_name == self.tag_member.name - assert isinstance(self.tag_member.type, QAPISchemaEnumType) + if not self.tag_member: # flat union + self.tag_member = seen.get(c_name(self._tag_name)) + base = "'base'" + # Pointing to the base type when not implicit would be + # nice, but we don't know it here + if not self.tag_member or self._tag_name != self.tag_member.name: + raise QAPISemError( + self.info, + "discriminator '%s' is not a member of %s" + % (self._tag_name, base)) + # Here we do: + base_type = schema.lookup_type(self.tag_member.defined_in) + assert base_type + if not base_type.is_implicit(): + base = "base type '%s'" % self.tag_member.defined_in + if not isinstance(self.tag_member.type, QAPISchemaEnumType): + raise QAPISemError( + self.info, + "discriminator member '%s' of %s must be of enum type" + % (self._tag_name, base)) + if self.tag_member.optional: + raise QAPISemError( + self.info, + "discriminator member '%s' of %s must not be optional" + % (self._tag_name, base)) + if self.tag_member.ifcond: + raise QAPISemError( + self.info, + "discriminator member '%s' of %s must not be conditional" + % (self._tag_name, base)) + else: # simple union + assert isinstance(self.tag_member.type, QAPISchemaEnumType) + assert not self.tag_member.optional + assert self.tag_member.ifcond == [] if self._tag_name: # flat union # branches that are not explicitly covered get an empty type cases = set([v.name for v in self.variants]) for m in self.tag_member.type.members: if m.name not in cases: - v = QAPISchemaObjectTypeVariant(m.name, 'q_empty', - m.ifcond) - v.set_owner(self.tag_member.owner) + v = QAPISchemaObjectTypeVariant(m.name, self.info, + 'q_empty', m.ifcond) + v.set_defined_in(self.tag_member.defined_in) self.variants.append(v) + if not self.variants: + raise QAPISemError(self.info, "union has no branches") for v in self.variants: v.check(schema) # Union names must match enum values; alternate names are # checked separately. Use 'seen' to tell the two apart. if seen: - assert v.name in self.tag_member.type.member_names() - assert isinstance(v.type, QAPISchemaObjectType) + if v.name not in self.tag_member.type.member_names(): + raise QAPISemError( + self.info, + "branch '%s' is not a value of %s" + % (v.name, self.tag_member.type.describe())) + if (not isinstance(v.type, QAPISchemaObjectType) + or v.type.variants): + raise QAPISemError( + self.info, + "%s cannot use %s" + % (v.describe(self.info), v.type.describe())) v.type.check(schema) def check_clash(self, info, seen): for v in self.variants: # Reset seen map for each variant, since qapi names from one # branch do not affect another branch - assert isinstance(v.type, QAPISchemaObjectType) v.type.check_clash(info, dict(seen)) class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember): role = 'branch' - def __init__(self, name, typ, ifcond=None): - QAPISchemaObjectTypeMember.__init__(self, name, typ, False, ifcond) + def __init__(self, name, info, typ, ifcond=None): + QAPISchemaObjectTypeMember.__init__(self, name, info, typ, + False, ifcond) class QAPISchemaAlternateType(QAPISchemaType): + meta = 'alternate' + def __init__(self, name, info, doc, ifcond, variants): QAPISchemaType.__init__(self, name, info, doc, ifcond) assert isinstance(variants, QAPISchemaObjectTypeVariants) assert variants.tag_member - variants.set_owner(name) - variants.tag_member.set_owner(self.name) + variants.set_defined_in(name) + variants.tag_member.set_defined_in(self.name) self.variants = variants def check(self, schema): @@ -1674,8 +1609,34 @@ class QAPISchemaAlternateType(QAPISchemaType): # Alternate branch names have no relation to the tag enum values; # so we have to check for potential name collisions ourselves. seen = {} + types_seen = {} for v in self.variants.variants: v.check_clash(self.info, seen) + qtype = v.type.alternate_qtype() + if not qtype: + raise QAPISemError( + self.info, + "%s cannot use %s" + % (v.describe(self.info), v.type.describe())) + conflicting = set([qtype]) + if qtype == 'QTYPE_QSTRING': + if isinstance(v.type, QAPISchemaEnumType): + for m in v.type.members: + if m.name in ['on', 'off']: + conflicting.add('QTYPE_QBOOL') + if re.match(r'[-+0-9.]', m.name): + # lazy, could be tightened + conflicting.add('QTYPE_QNUM') + else: + conflicting.add('QTYPE_QNUM') + conflicting.add('QTYPE_QBOOL') + for qt in conflicting: + if qt in types_seen: + raise QAPISemError( + self.info, + "%s can't be distinguished from '%s'" + % (v.describe(self.info), types_seen[qt])) + types_seen[qt] = v.name if self.doc: self.doc.connect_member(v) if self.doc: @@ -1688,14 +1649,14 @@ class QAPISchemaAlternateType(QAPISchemaType): return 'value' def visit(self, visitor): + QAPISchemaType.visit(self, visitor) visitor.visit_alternate_type(self.name, self.info, self.ifcond, self.variants) - def is_empty(self): - return False - class QAPISchemaCommand(QAPISchemaEntity): + meta = 'command' + def __init__(self, name, info, doc, ifcond, arg_type, ret_type, gen, success_response, boxed, allow_oob, allow_preconfig): QAPISchemaEntity.__init__(self, name, info, doc, ifcond) @@ -1714,24 +1675,33 @@ class QAPISchemaCommand(QAPISchemaEntity): def check(self, schema): QAPISchemaEntity.check(self, schema) if self._arg_type_name: - self.arg_type = schema.lookup_type(self._arg_type_name) - assert (isinstance(self.arg_type, QAPISchemaObjectType) or - isinstance(self.arg_type, QAPISchemaAlternateType)) - self.arg_type.check(schema) - if self.boxed: - if self.arg_type.is_empty(): - raise QAPISemError(self.info, - "Cannot use 'boxed' with empty type") - else: - assert not isinstance(self.arg_type, QAPISchemaAlternateType) - assert not self.arg_type.variants - elif self.boxed: - raise QAPISemError(self.info, "Use of 'boxed' requires 'data'") + self.arg_type = schema.resolve_type( + self._arg_type_name, self.info, "command's 'data'") + if not isinstance(self.arg_type, QAPISchemaObjectType): + raise QAPISemError( + self.info, + "command's 'data' cannot take %s" + % self.arg_type.describe()) + if self.arg_type.variants and not self.boxed: + raise QAPISemError( + self.info, + "command's 'data' can take %s only with 'boxed': true" + % self.arg_type.describe()) if self._ret_type_name: - self.ret_type = schema.lookup_type(self._ret_type_name) - assert isinstance(self.ret_type, QAPISchemaType) + self.ret_type = schema.resolve_type( + self._ret_type_name, self.info, "command's 'returns'") + if self.name not in returns_whitelist: + if not (isinstance(self.ret_type, QAPISchemaObjectType) + or (isinstance(self.ret_type, QAPISchemaArrayType) + and isinstance(self.ret_type.element_type, + QAPISchemaObjectType))): + raise QAPISemError( + self.info, + "command's 'returns' cannot take %s" + % self.ret_type.describe()) def visit(self, visitor): + QAPISchemaEntity.visit(self, visitor) visitor.visit_command(self.name, self.info, self.ifcond, self.arg_type, self.ret_type, self.gen, self.success_response, @@ -1740,6 +1710,8 @@ class QAPISchemaCommand(QAPISchemaEntity): class QAPISchemaEvent(QAPISchemaEntity): + meta = 'event' + def __init__(self, name, info, doc, ifcond, arg_type, boxed): QAPISchemaEntity.__init__(self, name, info, doc, ifcond) assert not arg_type or isinstance(arg_type, str) @@ -1750,21 +1722,21 @@ class QAPISchemaEvent(QAPISchemaEntity): def check(self, schema): QAPISchemaEntity.check(self, schema) if self._arg_type_name: - self.arg_type = schema.lookup_type(self._arg_type_name) - assert (isinstance(self.arg_type, QAPISchemaObjectType) or - isinstance(self.arg_type, QAPISchemaAlternateType)) - self.arg_type.check(schema) - if self.boxed: - if self.arg_type.is_empty(): - raise QAPISemError(self.info, - "Cannot use 'boxed' with empty type") - else: - assert not isinstance(self.arg_type, QAPISchemaAlternateType) - assert not self.arg_type.variants - elif self.boxed: - raise QAPISemError(self.info, "Use of 'boxed' requires 'data'") + self.arg_type = schema.resolve_type( + self._arg_type_name, self.info, "event's 'data'") + if not isinstance(self.arg_type, QAPISchemaObjectType): + raise QAPISemError( + self.info, + "event's 'data' cannot take %s" + % self.arg_type.describe()) + if self.arg_type.variants and not self.boxed: + raise QAPISemError( + self.info, + "event's 'data' can take %s only with 'boxed': true" + % self.arg_type.describe()) def visit(self, visitor): + QAPISchemaEntity.visit(self, visitor) visitor.visit_event(self.name, self.info, self.ifcond, self.arg_type, self.boxed) @@ -1772,11 +1744,7 @@ class QAPISchemaEvent(QAPISchemaEntity): class QAPISchema(object): def __init__(self, fname): self.fname = fname - if sys.version_info[0] >= 3: - f = open(fname, 'r', encoding='utf-8') - else: - f = open(fname, 'r') - parser = QAPISchemaParser(f) + parser = QAPISchemaParser(fname) exprs = check_exprs(parser.exprs) self.docs = parser.docs self._entity_list = [] @@ -1790,10 +1758,21 @@ class QAPISchema(object): def _def_entity(self, ent): # Only the predefined types are allowed to not have info assert ent.info or self._predefining - assert ent.name is None or ent.name not in self._entity_dict self._entity_list.append(ent) - if ent.name is not None: - self._entity_dict[ent.name] = ent + if ent.name is None: + return + # TODO reject names that differ only in '_' vs. '.' vs. '-', + # because they're liable to clash in generated C. + other_ent = self._entity_dict.get(ent.name) + if other_ent: + if other_ent.info: + where = QAPIError(other_ent.info, None, "previous definition") + raise QAPISemError( + ent.info, + "'%s' is already defined\n%s" % (ent.name, where)) + raise QAPISemError( + ent.info, "%s is already defined" % other_ent.describe()) + self._entity_dict[ent.name] = ent def lookup_entity(self, name, typ=None): ent = self._entity_dict.get(name) @@ -1804,13 +1783,22 @@ class QAPISchema(object): def lookup_type(self, name): return self.lookup_entity(name, QAPISchemaType) + def resolve_type(self, name, info, what): + typ = self.lookup_type(name) + if not typ: + if callable(what): + what = what(info) + raise QAPISemError( + info, "%s uses unknown type '%s'" % (what, name)) + return typ + def _def_include(self, expr, info, doc): include = expr['include'] assert doc is None main_info = info - while main_info['parent']: - main_info = main_info['parent'] - fname = os.path.relpath(include, os.path.dirname(main_info['file'])) + while main_info.parent: + main_info = main_info.parent + fname = os.path.relpath(include, os.path.dirname(main_info.fname)) self._def_entity(QAPISchemaInclude(fname, info)) def _def_builtin_type(self, name, json_type, c_type): @@ -1844,26 +1832,30 @@ class QAPISchema(object): qtypes = ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool'] - qtype_values = self._make_enum_members([{'name': n} for n in qtypes]) + qtype_values = self._make_enum_members( + [{'name': n} for n in qtypes], None) self._def_entity(QAPISchemaEnumType('QType', None, None, None, qtype_values, 'QTYPE')) - def _make_features(self, features): - return [QAPISchemaFeature(f['name'], f.get('if')) for f in features] + def _make_features(self, features, info): + return [QAPISchemaFeature(f['name'], info, f.get('if')) + for f in features] - def _make_enum_members(self, values): - return [QAPISchemaMember(v['name'], v.get('if')) for v in values] + def _make_enum_members(self, values, info): + return [QAPISchemaEnumMember(v['name'], info, v.get('if')) + for v in values] def _make_implicit_enum_type(self, name, info, ifcond, values): - # See also QAPISchemaObjectTypeMember._pretty_owner() - name = name + 'Kind' # Use namespace reserved by add_name() + # See also QAPISchemaObjectTypeMember.describe() + name = name + 'Kind' # reserved by check_defn_name_str() self._def_entity(QAPISchemaEnumType( - name, info, None, ifcond, self._make_enum_members(values), None)) + name, info, None, ifcond, self._make_enum_members(values, info), + None)) return name def _make_array_type(self, element_type, info): - name = element_type + 'List' # Use namespace reserved by add_name() + name = element_type + 'List' # reserved by check_defn_name_str() if not self.lookup_type(name): self._def_entity(QAPISchemaArrayType(name, info, element_type)) return name @@ -1872,7 +1864,7 @@ class QAPISchema(object): role, members): if not members: return None - # See also QAPISchemaObjectTypeMember._pretty_owner() + # See also QAPISchemaObjectTypeMember.describe() name = 'q_obj_%s-%s' % (name, role) typ = self.lookup_entity(name, QAPISchemaObjectType) if typ: @@ -1885,7 +1877,7 @@ class QAPISchema(object): # But it's not tight: the disjunction need not imply it. We # may end up compiling useless wrapper types. # TODO kill simple unions or implement the disjunction - assert ifcond == typ._ifcond # pylint: disable=protected-access + assert (ifcond or []) == typ._ifcond # pylint: disable=protected-access else: self._def_entity(QAPISchemaObjectType(name, info, doc, ifcond, None, members, None, [])) @@ -1898,7 +1890,7 @@ class QAPISchema(object): ifcond = expr.get('if') self._def_entity(QAPISchemaEnumType( name, info, doc, ifcond, - self._make_enum_members(data), prefix)) + self._make_enum_members(data, info), prefix)) def _make_member(self, name, typ, ifcond, info): optional = False @@ -1908,7 +1900,7 @@ class QAPISchema(object): if isinstance(typ, list): assert len(typ) == 1 typ = self._make_array_type(typ[0], info) - return QAPISchemaObjectTypeMember(name, typ, optional, ifcond) + return QAPISchemaObjectTypeMember(name, info, typ, optional, ifcond) def _make_members(self, data, info): return [self._make_member(key, value['type'], value.get('if'), info) @@ -1920,13 +1912,14 @@ class QAPISchema(object): data = expr['data'] ifcond = expr.get('if') features = expr.get('features', []) - self._def_entity(QAPISchemaObjectType(name, info, doc, ifcond, base, - self._make_members(data, info), - None, - self._make_features(features))) + self._def_entity(QAPISchemaObjectType( + name, info, doc, ifcond, base, + self._make_members(data, info), + None, + self._make_features(features, info))) - def _make_variant(self, case, typ, ifcond): - return QAPISchemaObjectTypeVariant(case, typ, ifcond) + def _make_variant(self, case, typ, ifcond, info): + return QAPISchemaObjectTypeVariant(case, info, typ, ifcond) def _make_simple_variant(self, case, typ, ifcond, info): if isinstance(typ, list): @@ -1935,7 +1928,7 @@ class QAPISchema(object): typ = self._make_implicit_object_type( typ, info, None, self.lookup_type(typ), 'wrapper', [self._make_member('data', typ, None, info)]) - return QAPISchemaObjectTypeVariant(case, typ, ifcond) + return QAPISchemaObjectTypeVariant(case, info, typ, ifcond) def _def_union_type(self, expr, info, doc): name = expr['union'] @@ -1949,7 +1942,8 @@ class QAPISchema(object): name, info, doc, ifcond, 'base', self._make_members(base, info)) if tag_name: - variants = [self._make_variant(key, value['type'], value.get('if')) + variants = [self._make_variant(key, value['type'], + value.get('if'), info) for (key, value) in data.items()] members = [] else: @@ -1958,26 +1952,26 @@ class QAPISchema(object): for (key, value) in data.items()] enum = [{'name': v.name, 'if': v.ifcond} for v in variants] typ = self._make_implicit_enum_type(name, info, ifcond, enum) - tag_member = QAPISchemaObjectTypeMember('type', typ, False) + tag_member = QAPISchemaObjectTypeMember('type', info, typ, False) members = [tag_member] self._def_entity( QAPISchemaObjectType(name, info, doc, ifcond, base, members, - QAPISchemaObjectTypeVariants(tag_name, - tag_member, - variants), [])) + QAPISchemaObjectTypeVariants( + tag_name, info, tag_member, variants), + [])) def _def_alternate_type(self, expr, info, doc): name = expr['alternate'] data = expr['data'] ifcond = expr.get('if') - variants = [self._make_variant(key, value['type'], value.get('if')) + variants = [self._make_variant(key, value['type'], value.get('if'), + info) for (key, value) in data.items()] - tag_member = QAPISchemaObjectTypeMember('type', 'QType', False) + tag_member = QAPISchemaObjectTypeMember('type', info, 'QType', False) self._def_entity( QAPISchemaAlternateType(name, info, doc, ifcond, - QAPISchemaObjectTypeVariants(None, - tag_member, - variants))) + QAPISchemaObjectTypeVariants( + None, info, tag_member, variants))) def _def_command(self, expr, info, doc): name = expr['command'] @@ -2269,7 +2263,7 @@ const QEnumLookup %(c_name)s_lookup = { def gen_enum(name, members, prefix=None): # append automatically generated _MAX value - enum_members = members + [QAPISchemaMember('_MAX')] + enum_members = members + [QAPISchemaEnumMember('_MAX', None)] ret = mcgen(''' diff --git a/scripts/qapi/events.py b/scripts/qapi/events.py index b732581046..7308e8e589 100644 --- a/scripts/qapi/events.py +++ b/scripts/qapi/events.py @@ -65,6 +65,8 @@ def gen_event_send(name, arg_type, boxed, event_enum_name, event_emit): # practice, we can rename our local variables with a leading _ prefix, # or split the code into a wrapper function that creates a boxed # 'param' object then calls another to do the real work. + have_args = boxed or (arg_type and not arg_type.is_empty()) + ret = mcgen(''' %(proto)s @@ -73,15 +75,13 @@ def gen_event_send(name, arg_type, boxed, event_enum_name, event_emit): ''', proto=build_event_send_proto(name, arg_type, boxed)) - if arg_type and not arg_type.is_empty(): + if have_args: ret += mcgen(''' QObject *obj; Visitor *v; ''') if not boxed: ret += gen_param_var(arg_type) - else: - assert not boxed ret += mcgen(''' @@ -90,7 +90,7 @@ def gen_event_send(name, arg_type, boxed, event_enum_name, event_emit): ''', name=name) - if arg_type and not arg_type.is_empty(): + if have_args: ret += mcgen(''' v = qobject_output_visitor_new(&obj); ''') @@ -121,7 +121,7 @@ def gen_event_send(name, arg_type, boxed, event_enum_name, event_emit): event_emit=event_emit, c_enum=c_enum_const(event_enum_name, name)) - if arg_type and not arg_type.is_empty(): + if have_args: ret += mcgen(''' visit_free(v); ''') @@ -194,7 +194,7 @@ void %(event_emit)s(%(event_enum)s event, QDict *qdict); self._event_emit_name)) # Note: we generate the enum member regardless of @ifcond, to # keep the enumeration usable in target-independent code. - self._event_enum_members.append(QAPISchemaMember(name)) + self._event_enum_members.append(QAPISchemaEnumMember(name, None)) def gen_events(schema, output_dir, prefix): diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c index a8a74d1dba..debb18f4aa 100644 --- a/scsi/qemu-pr-helper.c +++ b/scsi/qemu-pr-helper.c @@ -323,10 +323,10 @@ static int mpath_reconstruct_sense(int fd, int r, uint8_t *sense) */ uint8_t cdb[6] = { TEST_UNIT_READY }; int sz = 0; - int r = do_sgio(fd, cdb, sense, NULL, &sz, SG_DXFER_NONE); + int ret = do_sgio(fd, cdb, sense, NULL, &sz, SG_DXFER_NONE); - if (r != GOOD) { - return r; + if (ret != GOOD) { + return ret; } scsi_build_sense(sense, mpath_generic_sense(r)); return CHECK_CONDITION; diff --git a/target/alpha/fpu_helper.c b/target/alpha/fpu_helper.c index 62a066d902..df8b58963b 100644 --- a/target/alpha/fpu_helper.c +++ b/target/alpha/fpu_helper.c @@ -90,25 +90,18 @@ void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t ignore, uint32_t regno) uint32_t exc = env->error_code & ~ignore; if (exc) { env->fpcr |= exc; - exc &= ~ignore; -#ifdef CONFIG_USER_ONLY - /* - * In user mode, the kernel's software handler only - * delivers a signal if the exception is enabled. - */ - if (!(exc & env->fpcr_exc_enable)) { - return; - } -#else + exc &= env->fpcr_exc_enable; /* * In system mode, the software handler gets invoked * for any non-ignored exception. + * In user mode, the kernel's software handler only + * delivers a signal if the exception is enabled. */ +#ifdef CONFIG_USER_ONLY if (!exc) { return; } #endif - exc &= env->fpcr_exc_enable; fp_exc_raise1(env, GETPC(), exc, regno, EXC_M_SWC); } } diff --git a/target/alpha/helper.c b/target/alpha/helper.c index 19cda0a2db..55d7274d94 100644 --- a/target/alpha/helper.c +++ b/target/alpha/helper.c @@ -36,53 +36,53 @@ uint64_t cpu_alpha_load_fpcr(CPUAlphaState *env) void cpu_alpha_store_fpcr(CPUAlphaState *env, uint64_t val) { + static const uint8_t rm_map[] = { + [FPCR_DYN_NORMAL >> FPCR_DYN_SHIFT] = float_round_nearest_even, + [FPCR_DYN_CHOPPED >> FPCR_DYN_SHIFT] = float_round_to_zero, + [FPCR_DYN_MINUS >> FPCR_DYN_SHIFT] = float_round_down, + [FPCR_DYN_PLUS >> FPCR_DYN_SHIFT] = float_round_up, + }; + uint32_t fpcr = val >> 32; uint32_t t = 0; + /* Record the raw value before adjusting for linux-user. */ + env->fpcr = fpcr; + +#ifdef CONFIG_USER_ONLY + /* + * Override some of these bits with the contents of ENV->SWCR. + * In system mode, some of these would trap to the kernel, at + * which point the kernel's handler would emulate and apply + * the software exception mask. + */ + uint32_t soft_fpcr = alpha_ieee_swcr_to_fpcr(env->swcr) >> 32; + fpcr |= soft_fpcr & (FPCR_STATUS_MASK | FPCR_DNZ); + + /* + * The IOV exception is disabled by the kernel with SWCR_TRAP_ENABLE_INV, + * which got mapped by alpha_ieee_swcr_to_fpcr to FPCR_INVD. + * Add FPCR_IOV to fpcr_exc_enable so that it is handled identically. + */ + t |= CONVERT_BIT(soft_fpcr, FPCR_INVD, FPCR_IOV); +#endif + t |= CONVERT_BIT(fpcr, FPCR_INED, FPCR_INE); t |= CONVERT_BIT(fpcr, FPCR_UNFD, FPCR_UNF); t |= CONVERT_BIT(fpcr, FPCR_OVFD, FPCR_OVF); t |= CONVERT_BIT(fpcr, FPCR_DZED, FPCR_DZE); t |= CONVERT_BIT(fpcr, FPCR_INVD, FPCR_INV); - env->fpcr = fpcr; env->fpcr_exc_enable = ~t & FPCR_STATUS_MASK; - switch (fpcr & FPCR_DYN_MASK) { - case FPCR_DYN_NORMAL: - default: - t = float_round_nearest_even; - break; - case FPCR_DYN_CHOPPED: - t = float_round_to_zero; - break; - case FPCR_DYN_MINUS: - t = float_round_down; - break; - case FPCR_DYN_PLUS: - t = float_round_up; - break; - } - env->fpcr_dyn_round = t; - - env->fpcr_flush_to_zero = (fpcr & FPCR_UNFD) && (fpcr & FPCR_UNDZ); + env->fpcr_dyn_round = rm_map[(fpcr & FPCR_DYN_MASK) >> FPCR_DYN_SHIFT]; env->fp_status.flush_inputs_to_zero = (fpcr & FPCR_DNZ) != 0; + t = (fpcr & FPCR_UNFD) && (fpcr & FPCR_UNDZ); #ifdef CONFIG_USER_ONLY - /* - * Override some of these bits with the contents of ENV->SWCR. - * In system mode, some of these would trap to the kernel, at - * which point the kernel's handler would emulate and apply - * the software exception mask. - */ - if (env->swcr & SWCR_MAP_DMZ) { - env->fp_status.flush_inputs_to_zero = 1; - } - if (env->swcr & SWCR_MAP_UMZ) { - env->fp_status.flush_to_zero = 1; - } - env->fpcr_exc_enable &= ~(alpha_ieee_swcr_to_fpcr(env->swcr) >> 32); + t |= (env->swcr & SWCR_MAP_UMZ) != 0; #endif + env->fpcr_flush_to_zero = t; } uint64_t helper_load_fpcr(CPUAlphaState *env) diff --git a/target/arm/helper.c b/target/arm/helper.c index 507026c915..0d9a2d2ab7 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6733,6 +6733,19 @@ void register_cp_regs_for_features(ARMCPU *cpu) } if (arm_feature(env, ARM_FEATURE_CBAR)) { + /* + * CBAR is IMPDEF, but common on Arm Cortex-A implementations. + * There are two flavours: + * (1) older 32-bit only cores have a simple 32-bit CBAR + * (2) 64-bit cores have a 64-bit CBAR visible to AArch64, plus a + * 32-bit register visible to AArch32 at a different encoding + * to the "flavour 1" register and with the bits rearranged to + * be able to squash a 64-bit address into the 32-bit view. + * We distinguish the two via the ARM_FEATURE_AARCH64 flag, but + * in future if we support AArch32-only configs of some of the + * AArch64 cores we might need to add a specific feature flag + * to indicate cores with "flavour 2" CBAR. + */ if (arm_feature(env, ARM_FEATURE_AARCH64)) { /* 32 bit view is [31:18] 0...0 [43:32]. */ uint32_t cbar32 = (extract64(cpu->reset_cbar, 18, 14) << 18) @@ -6740,12 +6753,12 @@ void register_cp_regs_for_features(ARMCPU *cpu) ARMCPRegInfo cbar_reginfo[] = { { .name = "CBAR", .type = ARM_CP_CONST, - .cp = 15, .crn = 15, .crm = 0, .opc1 = 4, .opc2 = 0, - .access = PL1_R, .resetvalue = cpu->reset_cbar }, + .cp = 15, .crn = 15, .crm = 3, .opc1 = 1, .opc2 = 0, + .access = PL1_R, .resetvalue = cbar32 }, { .name = "CBAR_EL1", .state = ARM_CP_STATE_AA64, .type = ARM_CP_CONST, .opc0 = 3, .opc1 = 1, .crn = 15, .crm = 3, .opc2 = 0, - .access = PL1_R, .resetvalue = cbar32 }, + .access = PL1_R, .resetvalue = cpu->reset_cbar }, REGINFO_SENTINEL }; /* We don't implement a r/w 64 bit CBAR currently */ @@ -8339,88 +8352,32 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) new_el, env->pc, pstate_read(env)); } -static inline bool check_for_semihosting(CPUState *cs) -{ +/* + * Do semihosting call and set the appropriate return value. All the + * permission and validity checks have been done at translate time. + * + * We only see semihosting exceptions in TCG only as they are not + * trapped to the hypervisor in KVM. + */ #ifdef CONFIG_TCG - /* Check whether this exception is a semihosting call; if so - * then handle it and return true; otherwise return false. - */ +static void handle_semihosting(CPUState *cs) +{ ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; if (is_a64(env)) { - if (cs->exception_index == EXCP_SEMIHOST) { - /* This is always the 64-bit semihosting exception. - * The "is this usermode" and "is semihosting enabled" - * checks have been done at translate time. - */ - qemu_log_mask(CPU_LOG_INT, - "...handling as semihosting call 0x%" PRIx64 "\n", - env->xregs[0]); - env->xregs[0] = do_arm_semihosting(env); - return true; - } - return false; + qemu_log_mask(CPU_LOG_INT, + "...handling as semihosting call 0x%" PRIx64 "\n", + env->xregs[0]); + env->xregs[0] = do_arm_semihosting(env); } else { - uint32_t imm; - - /* Only intercept calls from privileged modes, to provide some - * semblance of security. - */ - if (cs->exception_index != EXCP_SEMIHOST && - (!semihosting_enabled() || - ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR))) { - return false; - } - - switch (cs->exception_index) { - case EXCP_SEMIHOST: - /* This is always a semihosting call; the "is this usermode" - * and "is semihosting enabled" checks have been done at - * translate time. - */ - break; - case EXCP_SWI: - /* Check for semihosting interrupt. */ - if (env->thumb) { - imm = arm_lduw_code(env, env->regs[15] - 2, arm_sctlr_b(env)) - & 0xff; - if (imm == 0xab) { - break; - } - } else { - imm = arm_ldl_code(env, env->regs[15] - 4, arm_sctlr_b(env)) - & 0xffffff; - if (imm == 0x123456) { - break; - } - } - return false; - case EXCP_BKPT: - /* See if this is a semihosting syscall. */ - if (env->thumb) { - imm = arm_lduw_code(env, env->regs[15], arm_sctlr_b(env)) - & 0xff; - if (imm == 0xab) { - env->regs[15] += 2; - break; - } - } - return false; - default: - return false; - } - qemu_log_mask(CPU_LOG_INT, "...handling as semihosting call 0x%x\n", env->regs[0]); env->regs[0] = do_arm_semihosting(env); - return true; } -#else - return false; -#endif } +#endif /* Handle a CPU exception for A and R profile CPUs. * Do any appropriate logging, handle PSCI calls, and then hand off @@ -8451,13 +8408,17 @@ void arm_cpu_do_interrupt(CPUState *cs) return; } - /* Semihosting semantics depend on the register width of the - * code that caused the exception, not the target exception level, - * so must be handled here. + /* + * Semihosting semantics depend on the register width of the code + * that caused the exception, not the target exception level, so + * must be handled here. */ - if (check_for_semihosting(cs)) { +#ifdef CONFIG_TCG + if (cs->exception_index == EXCP_SEMIHOST) { + handle_semihosting(cs); return; } +#endif /* Hooks may change global state so BQL should be held, also the * BQL needs to be held for any modification of diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c index 884d35d2b0..27cd2f3f96 100644 --- a/target/arm/m_helper.c +++ b/target/arm/m_helper.c @@ -2114,19 +2114,13 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) break; } break; + case EXCP_SEMIHOST: + qemu_log_mask(CPU_LOG_INT, + "...handling as semihosting call 0x%x\n", + env->regs[0]); + env->regs[0] = do_arm_semihosting(env); + return; case EXCP_BKPT: - if (semihosting_enabled()) { - int nr; - nr = arm_lduw_code(env, env->regs[15], arm_sctlr_b(env)) & 0xff; - if (nr == 0xab) { - env->regs[15] += 2; - qemu_log_mask(CPU_LOG_INT, - "...handling as semihosting call 0x%x\n", - env->regs[0]); - env->regs[0] = do_arm_semihosting(env); - return; - } - } armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG, false); break; case EXCP_IRQ: diff --git a/target/arm/translate.c b/target/arm/translate.c index 34bb280e3d..698c594e8c 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -8424,7 +8424,16 @@ static bool trans_BKPT(DisasContext *s, arg_BKPT *a) if (!ENABLE_ARCH_5) { return false; } - gen_exception_bkpt_insn(s, syn_aa32_bkpt(a->imm, false)); + if (arm_dc_feature(s, ARM_FEATURE_M) && + semihosting_enabled() && +#ifndef CONFIG_USER_ONLY + !IS_USER(s) && +#endif + (a->imm == 0xab)) { + gen_exception_internal_insn(s, s->base.pc_next, EXCP_SEMIHOST); + } else { + gen_exception_bkpt_insn(s, syn_aa32_bkpt(a->imm, false)); + } return true; } @@ -10213,14 +10222,25 @@ static bool trans_CBZ(DisasContext *s, arg_CBZ *a) } /* - * Supervisor call + * Supervisor call - both T32 & A32 come here so we need to check + * which mode we are in when checking for semihosting. */ static bool trans_SVC(DisasContext *s, arg_SVC *a) { - gen_set_pc_im(s, s->base.pc_next); - s->svc_imm = a->imm; - s->base.is_jmp = DISAS_SWI; + const uint32_t semihost_imm = s->thumb ? 0xab : 0x123456; + + if (!arm_dc_feature(s, ARM_FEATURE_M) && semihosting_enabled() && +#ifndef CONFIG_USER_ONLY + !IS_USER(s) && +#endif + (a->imm == semihost_imm)) { + gen_exception_internal_insn(s, s->base.pc_next, EXCP_SEMIHOST); + } else { + gen_set_pc_im(s, s->base.pc_next); + s->svc_imm = a->imm; + s->base.is_jmp = DISAS_SWI; + } return true; } diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 9e0bac31e8..44f1bbdcac 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -789,7 +789,7 @@ typedef struct FeatureWordInfo { * In cases of disagreement between feature naming conventions, * aliases may be added. */ - const char *feat_names[32]; + const char *feat_names[64]; union { /* If type==CPUID_FEATURE_WORD */ struct { @@ -801,17 +801,13 @@ typedef struct FeatureWordInfo { /* If type==MSR_FEATURE_WORD */ struct { uint32_t index; - struct { /*CPUID that enumerate this MSR*/ - FeatureWord cpuid_class; - uint32_t cpuid_flag; - } cpuid_dep; } msr; }; - uint32_t tcg_features; /* Feature flags supported by TCG */ - uint32_t unmigratable_flags; /* Feature flags known to be unmigratable */ - uint32_t migratable_flags; /* Feature flags known to be migratable */ + uint64_t tcg_features; /* Feature flags supported by TCG */ + uint64_t unmigratable_flags; /* Feature flags known to be unmigratable */ + uint64_t migratable_flags; /* Feature flags known to be migratable */ /* Features that shouldn't be auto-enabled by "-cpu host" */ - uint32_t no_autoenable_flags; + uint64_t no_autoenable_flags; } FeatureWordInfo; static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { @@ -1134,7 +1130,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { [FEAT_8000_0008_EBX] = { .type = CPUID_FEATURE_WORD, .feat_names = { - NULL, NULL, NULL, NULL, + "clzero", NULL, "xsaveerptr", NULL, NULL, NULL, NULL, NULL, NULL, "wbnoinvd", NULL, NULL, "ibpb", NULL, NULL, NULL, @@ -1218,10 +1214,6 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { }, .msr = { .index = MSR_IA32_ARCH_CAPABILITIES, - .cpuid_dep = { - FEAT_7_0_EDX, - CPUID_7_0_EDX_ARCH_CAPABILITIES - } }, }, [FEAT_CORE_CAPABILITY] = { @@ -1238,12 +1230,253 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { }, .msr = { .index = MSR_IA32_CORE_CAPABILITY, - .cpuid_dep = { - FEAT_7_0_EDX, - CPUID_7_0_EDX_CORE_CAPABILITY, - }, }, }, + + [FEAT_VMX_PROCBASED_CTLS] = { + .type = MSR_FEATURE_WORD, + .feat_names = { + NULL, NULL, "vmx-vintr-pending", "vmx-tsc-offset", + NULL, NULL, NULL, "vmx-hlt-exit", + NULL, "vmx-invlpg-exit", "vmx-mwait-exit", "vmx-rdpmc-exit", + "vmx-rdtsc-exit", NULL, NULL, "vmx-cr3-load-noexit", + "vmx-cr3-store-noexit", NULL, NULL, "vmx-cr8-load-exit", + "vmx-cr8-store-exit", "vmx-flexpriority", "vmx-vnmi-pending", "vmx-movdr-exit", + "vmx-io-exit", "vmx-io-bitmap", NULL, "vmx-mtf", + "vmx-msr-bitmap", "vmx-monitor-exit", "vmx-pause-exit", "vmx-secondary-ctls", + }, + .msr = { + .index = MSR_IA32_VMX_TRUE_PROCBASED_CTLS, + } + }, + + [FEAT_VMX_SECONDARY_CTLS] = { + .type = MSR_FEATURE_WORD, + .feat_names = { + "vmx-apicv-xapic", "vmx-ept", "vmx-desc-exit", "vmx-rdtscp-exit", + "vmx-apicv-x2apic", "vmx-vpid", "vmx-wbinvd-exit", "vmx-unrestricted-guest", + "vmx-apicv-register", "vmx-apicv-vid", "vmx-ple", "vmx-rdrand-exit", + "vmx-invpcid-exit", "vmx-vmfunc", "vmx-shadow-vmcs", "vmx-encls-exit", + "vmx-rdseed-exit", "vmx-pml", NULL, NULL, + "vmx-xsaves", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, + .msr = { + .index = MSR_IA32_VMX_PROCBASED_CTLS2, + } + }, + + [FEAT_VMX_PINBASED_CTLS] = { + .type = MSR_FEATURE_WORD, + .feat_names = { + "vmx-intr-exit", NULL, NULL, "vmx-nmi-exit", + NULL, "vmx-vnmi", "vmx-preemption-timer", "vmx-posted-intr", + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, + .msr = { + .index = MSR_IA32_VMX_TRUE_PINBASED_CTLS, + } + }, + + [FEAT_VMX_EXIT_CTLS] = { + .type = MSR_FEATURE_WORD, + /* + * VMX_VM_EXIT_HOST_ADDR_SPACE_SIZE is copied from + * the LM CPUID bit. + */ + .feat_names = { + NULL, NULL, "vmx-exit-nosave-debugctl", NULL, + NULL, NULL, NULL, NULL, + NULL, NULL /* vmx-exit-host-addr-space-size */, NULL, NULL, + "vmx-exit-load-perf-global-ctrl", NULL, NULL, "vmx-exit-ack-intr", + NULL, NULL, "vmx-exit-save-pat", "vmx-exit-load-pat", + "vmx-exit-save-efer", "vmx-exit-load-efer", + "vmx-exit-save-preemption-timer", "vmx-exit-clear-bndcfgs", + NULL, "vmx-exit-clear-rtit-ctl", NULL, NULL, + NULL, NULL, NULL, NULL, + }, + .msr = { + .index = MSR_IA32_VMX_TRUE_EXIT_CTLS, + } + }, + + [FEAT_VMX_ENTRY_CTLS] = { + .type = MSR_FEATURE_WORD, + .feat_names = { + NULL, NULL, "vmx-entry-noload-debugctl", NULL, + NULL, NULL, NULL, NULL, + NULL, "vmx-entry-ia32e-mode", NULL, NULL, + NULL, "vmx-entry-load-perf-global-ctrl", "vmx-entry-load-pat", "vmx-entry-load-efer", + "vmx-entry-load-bndcfgs", NULL, "vmx-entry-load-rtit-ctl", NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, + .msr = { + .index = MSR_IA32_VMX_TRUE_ENTRY_CTLS, + } + }, + + [FEAT_VMX_MISC] = { + .type = MSR_FEATURE_WORD, + .feat_names = { + NULL, NULL, NULL, NULL, + NULL, "vmx-store-lma", "vmx-activity-hlt", "vmx-activity-shutdown", + "vmx-activity-wait-sipi", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, "vmx-vmwrite-vmexit-fields", "vmx-zero-len-inject", NULL, + }, + .msr = { + .index = MSR_IA32_VMX_MISC, + } + }, + + [FEAT_VMX_EPT_VPID_CAPS] = { + .type = MSR_FEATURE_WORD, + .feat_names = { + "vmx-ept-execonly", NULL, NULL, NULL, + NULL, NULL, "vmx-page-walk-4", "vmx-page-walk-5", + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + "vmx-ept-2mb", "vmx-ept-1gb", NULL, NULL, + "vmx-invept", "vmx-eptad", "vmx-ept-advanced-exitinfo", NULL, + NULL, "vmx-invept-single-context", "vmx-invept-all-context", NULL, + NULL, NULL, NULL, NULL, + "vmx-invvpid", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + "vmx-invvpid-single-addr", "vmx-invept-single-context", + "vmx-invvpid-all-context", "vmx-invept-single-context-noglobals", + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, + .msr = { + .index = MSR_IA32_VMX_EPT_VPID_CAP, + } + }, + + [FEAT_VMX_BASIC] = { + .type = MSR_FEATURE_WORD, + .feat_names = { + [54] = "vmx-ins-outs", + [55] = "vmx-true-ctls", + }, + .msr = { + .index = MSR_IA32_VMX_BASIC, + }, + /* Just to be safe - we don't support setting the MSEG version field. */ + .no_autoenable_flags = MSR_VMX_BASIC_DUAL_MONITOR, + }, + + [FEAT_VMX_VMFUNC] = { + .type = MSR_FEATURE_WORD, + .feat_names = { + [0] = "vmx-eptp-switching", + }, + .msr = { + .index = MSR_IA32_VMX_VMFUNC, + } + }, + +}; + +typedef struct FeatureMask { + FeatureWord index; + uint64_t mask; +} FeatureMask; + +typedef struct FeatureDep { + FeatureMask from, to; +} FeatureDep; + +static FeatureDep feature_dependencies[] = { + { + .from = { FEAT_7_0_EDX, CPUID_7_0_EDX_ARCH_CAPABILITIES }, + .to = { FEAT_ARCH_CAPABILITIES, ~0ull }, + }, + { + .from = { FEAT_7_0_EDX, CPUID_7_0_EDX_CORE_CAPABILITY }, + .to = { FEAT_CORE_CAPABILITY, ~0ull }, + }, + { + .from = { FEAT_1_ECX, CPUID_EXT_VMX }, + .to = { FEAT_VMX_PROCBASED_CTLS, ~0ull }, + }, + { + .from = { FEAT_1_ECX, CPUID_EXT_VMX }, + .to = { FEAT_VMX_PINBASED_CTLS, ~0ull }, + }, + { + .from = { FEAT_1_ECX, CPUID_EXT_VMX }, + .to = { FEAT_VMX_EXIT_CTLS, ~0ull }, + }, + { + .from = { FEAT_1_ECX, CPUID_EXT_VMX }, + .to = { FEAT_VMX_ENTRY_CTLS, ~0ull }, + }, + { + .from = { FEAT_1_ECX, CPUID_EXT_VMX }, + .to = { FEAT_VMX_MISC, ~0ull }, + }, + { + .from = { FEAT_1_ECX, CPUID_EXT_VMX }, + .to = { FEAT_VMX_BASIC, ~0ull }, + }, + { + .from = { FEAT_8000_0001_EDX, CPUID_EXT2_LM }, + .to = { FEAT_VMX_ENTRY_CTLS, VMX_VM_ENTRY_IA32E_MODE }, + }, + { + .from = { FEAT_VMX_PROCBASED_CTLS, VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS }, + .to = { FEAT_VMX_SECONDARY_CTLS, ~0ull }, + }, + { + .from = { FEAT_XSAVE, CPUID_XSAVE_XSAVES }, + .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_XSAVES }, + }, + { + .from = { FEAT_1_ECX, CPUID_EXT_RDRAND }, + .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_RDRAND_EXITING }, + }, + { + .from = { FEAT_7_0_EBX, CPUID_7_0_EBX_INVPCID }, + .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_INVPCID }, + }, + { + .from = { FEAT_7_0_EBX, CPUID_7_0_EBX_RDSEED }, + .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_RDSEED_EXITING }, + }, + { + .from = { FEAT_8000_0001_EDX, CPUID_EXT2_RDTSCP }, + .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_RDTSCP }, + }, + { + .from = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_EPT }, + .to = { FEAT_VMX_EPT_VPID_CAPS, 0xffffffffull }, + }, + { + .from = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_EPT }, + .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST }, + }, + { + .from = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_VPID }, + .to = { FEAT_VMX_EPT_VPID_CAPS, 0xffffffffull << 32 }, + }, + { + .from = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_VMFUNC }, + .to = { FEAT_VMX_VMFUNC, ~0ull }, + }, }; typedef struct X86RegisterInfo32 { @@ -1354,14 +1587,14 @@ const char *get_register_name_32(unsigned int reg) * Returns the set of feature flags that are supported and migratable by * QEMU, for a given FeatureWord. */ -static uint32_t x86_cpu_get_migratable_flags(FeatureWord w) +static uint64_t x86_cpu_get_migratable_flags(FeatureWord w) { FeatureWordInfo *wi = &feature_word_info[w]; - uint32_t r = 0; + uint64_t r = 0; int i; - for (i = 0; i < 32; i++) { - uint32_t f = 1U << i; + for (i = 0; i < 64; i++) { + uint64_t f = 1ULL << i; /* If the feature name is known, it is implicitly considered migratable, * unless it is explicitly set in unmigratable_flags */ @@ -2923,7 +3156,7 @@ void x86_cpu_change_kvm_default(const char *prop, const char *value) assert(pv->prop); } -static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w, +static uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, bool migratable_only); static bool lmce_supported(void) @@ -3096,17 +3329,41 @@ static char *feature_word_description(FeatureWordInfo *f, uint32_t bit) return NULL; } -static void report_unavailable_features(FeatureWord w, uint32_t mask) +static bool x86_cpu_have_filtered_features(X86CPU *cpu) { + FeatureWord w; + + for (w = 0; w < FEATURE_WORDS; w++) { + if (cpu->filtered_features[w]) { + return true; + } + } + + return false; +} + +static void mark_unavailable_features(X86CPU *cpu, FeatureWord w, uint64_t mask, + const char *verbose_prefix) +{ + CPUX86State *env = &cpu->env; FeatureWordInfo *f = &feature_word_info[w]; int i; char *feat_word_str; - for (i = 0; i < 32; ++i) { - if ((1UL << i) & mask) { + if (!cpu->force_features) { + env->features[w] &= ~mask; + } + cpu->filtered_features[w] |= mask; + + if (!verbose_prefix) { + return; + } + + for (i = 0; i < 64; ++i) { + if ((1ULL << i) & mask) { feat_word_str = feature_word_description(f, i); - warn_report("%s doesn't support requested feature: %s%s%s [bit %d]", - accel_uses_host_cpuid() ? "host" : "TCG", + warn_report("%s: %s%s%s [bit %d]", + verbose_prefix, feat_word_str, f->feat_names[i] ? "." : "", f->feat_names[i] ? f->feat_names[i] : "", i); @@ -3346,7 +3603,7 @@ static void x86_cpu_get_feature_words(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - uint32_t *array = (uint32_t *)opaque; + uint64_t *array = (uint64_t *)opaque; FeatureWord w; X86CPUFeatureWordInfo word_infos[FEATURE_WORDS] = { }; X86CPUFeatureWordInfoList list_entries[FEATURE_WORDS] = { }; @@ -3390,6 +3647,7 @@ static inline void feat2prop(char *s) /* Return the feature property name for a feature flag bit */ static const char *x86_cpu_feature_name(FeatureWord w, int bitnr) { + const char *name; /* XSAVE components are automatically enabled by other features, * so return the original feature name instead */ @@ -3403,9 +3661,11 @@ static const char *x86_cpu_feature_name(FeatureWord w, int bitnr) } } - assert(bitnr < 32); + assert(bitnr < 64); assert(w < FEATURE_WORDS); - return feature_word_info[w].feat_names[bitnr]; + name = feature_word_info[w].feat_names[bitnr]; + assert(bitnr < 32 || !(name && feature_word_info[w].type == CPUID_FEATURE_WORD)); + return name; } /* Compatibily hack to maintain legacy +-feat semantic, @@ -3511,7 +3771,7 @@ static void x86_cpu_parse_featurestr(const char *typename, char *features, } static void x86_cpu_expand_features(X86CPU *cpu, Error **errp); -static int x86_cpu_filter_features(X86CPU *cpu); +static void x86_cpu_filter_features(X86CPU *cpu, bool verbose); /* Build a list with the name of all features on a feature word array */ static void x86_cpu_list_feature_names(FeatureWordArray features, @@ -3521,10 +3781,10 @@ static void x86_cpu_list_feature_names(FeatureWordArray features, strList **next = feat_names; for (w = 0; w < FEATURE_WORDS; w++) { - uint32_t filtered = features[w]; + uint64_t filtered = features[w]; int i; - for (i = 0; i < 32; i++) { - if (filtered & (1UL << i)) { + for (i = 0; i < 64; i++) { + if (filtered & (1ULL << i)) { strList *new = g_new0(strList, 1); new->value = g_strdup(x86_cpu_feature_name(w, i)); *next = new; @@ -3576,7 +3836,7 @@ static void x86_cpu_class_check_missing_features(X86CPUClass *xcc, next = &new->next; } - x86_cpu_filter_features(xc); + x86_cpu_filter_features(xc, false); x86_cpu_list_feature_names(xc->filtered_features, next); @@ -3693,7 +3953,7 @@ void x86_cpu_list(void) names = NULL; for (i = 0; i < ARRAY_SIZE(feature_word_info); i++) { FeatureWordInfo *fw = &feature_word_info[i]; - for (j = 0; j < 32; j++) { + for (j = 0; j < 64; j++) { if (fw->feat_names[j]) { names = g_list_append(names, (gpointer)fw->feat_names[j]); } @@ -3748,11 +4008,11 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) return cpu_list; } -static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w, +static uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, bool migratable_only) { FeatureWordInfo *wi = &feature_word_info[w]; - uint32_t r = 0; + uint64_t r = 0; if (kvm_enabled()) { switch (wi->type) { @@ -3784,15 +4044,6 @@ static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w, return r; } -static void x86_cpu_report_filtered_features(X86CPU *cpu) -{ - FeatureWord w; - - for (w = 0; w < FEATURE_WORDS; w++) { - report_unavailable_features(w, cpu->filtered_features[w]); - } -} - static void x86_cpu_apply_props(X86CPU *cpu, PropValue *props) { PropValue *pv; @@ -3932,7 +4183,7 @@ static QDict *x86_cpu_static_props(void) for (w = 0; w < FEATURE_WORDS; w++) { FeatureWordInfo *fi = &feature_word_info[w]; int bit; - for (bit = 0; bit < 32; bit++) { + for (bit = 0; bit < 64; bit++) { if (!fi->feat_names[bit]) { continue; } @@ -5048,9 +5299,26 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp) { CPUX86State *env = &cpu->env; FeatureWord w; + int i; GList *l; Error *local_err = NULL; + for (l = plus_features; l; l = l->next) { + const char *prop = l->data; + object_property_set_bool(OBJECT(cpu), true, prop, &local_err); + if (local_err) { + goto out; + } + } + + for (l = minus_features; l; l = l->next) { + const char *prop = l->data; + object_property_set_bool(OBJECT(cpu), false, prop, &local_err); + if (local_err) { + goto out; + } + } + /*TODO: Now cpu->max_features doesn't overwrite features * set using QOM properties, and we can convert * plus_features & minus_features to global properties @@ -5068,19 +5336,18 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp) } } - for (l = plus_features; l; l = l->next) { - const char *prop = l->data; - object_property_set_bool(OBJECT(cpu), true, prop, &local_err); - if (local_err) { - goto out; - } - } + for (i = 0; i < ARRAY_SIZE(feature_dependencies); i++) { + FeatureDep *d = &feature_dependencies[i]; + if (!(env->features[d->from.index] & d->from.mask)) { + uint64_t unavailable_features = env->features[d->to.index] & d->to.mask; - for (l = minus_features; l; l = l->next) { - const char *prop = l->data; - object_property_set_bool(OBJECT(cpu), false, prop, &local_err); - if (local_err) { - goto out; + /* Not an error unless the dependent feature was added explicitly. */ + mark_unavailable_features(cpu, d->to.index, + unavailable_features & env->user_features[d->to.index], + "This feature depends on other features that were not requested"); + + env->user_features[d->to.index] |= unavailable_features; + env->features[d->to.index] &= ~unavailable_features; } } @@ -5154,24 +5421,24 @@ out: * * Returns: 0 if all flags are supported by the host, non-zero otherwise. */ -static int x86_cpu_filter_features(X86CPU *cpu) +static void x86_cpu_filter_features(X86CPU *cpu, bool verbose) { CPUX86State *env = &cpu->env; FeatureWord w; - int rv = 0; + const char *prefix = NULL; + + if (verbose) { + prefix = accel_uses_host_cpuid() + ? "host doesn't support requested feature" + : "TCG doesn't support requested feature"; + } for (w = 0; w < FEATURE_WORDS; w++) { - uint32_t host_feat = + uint64_t host_feat = x86_cpu_get_supported_feature_word(w, false); - uint32_t requested_features = env->features[w]; - uint32_t available_features = requested_features & host_feat; - if (!cpu->force_features) { - env->features[w] = available_features; - } - cpu->filtered_features[w] = requested_features & ~available_features; - if (cpu->filtered_features[w]) { - rv = 1; - } + uint64_t requested_features = env->features[w]; + uint64_t unavailable_features = requested_features & ~host_feat; + mark_unavailable_features(cpu, w, unavailable_features, prefix); } if ((env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_INTEL_PT) && @@ -5197,13 +5464,9 @@ static int x86_cpu_filter_features(X86CPU *cpu) * host can't emulate the capabilities we report on * cpu_x86_cpuid(), intel-pt can't be enabled on the current host. */ - env->features[FEAT_7_0_EBX] &= ~CPUID_7_0_EBX_INTEL_PT; - cpu->filtered_features[FEAT_7_0_EBX] |= CPUID_7_0_EBX_INTEL_PT; - rv = 1; + mark_unavailable_features(cpu, FEAT_7_0_EBX, CPUID_7_0_EBX_INTEL_PT, prefix); } } - - return rv; } static void x86_cpu_realizefn(DeviceState *dev, Error **errp) @@ -5244,16 +5507,14 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) goto out; } - if (x86_cpu_filter_features(cpu) && - (cpu->check_cpuid || cpu->enforce_cpuid)) { - x86_cpu_report_filtered_features(cpu); - if (cpu->enforce_cpuid) { - error_setg(&local_err, - accel_uses_host_cpuid() ? - "Host doesn't support requested features" : - "TCG doesn't support requested features"); - goto out; - } + x86_cpu_filter_features(cpu, cpu->check_cpuid || cpu->enforce_cpuid); + + if (cpu->enforce_cpuid && x86_cpu_have_filtered_features(cpu)) { + error_setg(&local_err, + accel_uses_host_cpuid() ? + "Host doesn't support requested features" : + "TCG doesn't support requested features"); + goto out; } /* On AMD CPUs, some CPUID[8000_0001].EDX bits must match the bits on @@ -5473,7 +5734,7 @@ static void x86_cpu_unrealizefn(DeviceState *dev, Error **errp) typedef struct BitProperty { FeatureWord w; - uint32_t mask; + uint64_t mask; } BitProperty; static void x86_cpu_get_bit_prop(Object *obj, Visitor *v, const char *name, @@ -5481,7 +5742,7 @@ static void x86_cpu_get_bit_prop(Object *obj, Visitor *v, const char *name, { X86CPU *cpu = X86_CPU(obj); BitProperty *fp = opaque; - uint32_t f = cpu->env.features[fp->w]; + uint64_t f = cpu->env.features[fp->w]; bool value = (f & fp->mask) == fp->mask; visit_type_bool(v, name, &value, errp); } @@ -5534,7 +5795,7 @@ static void x86_cpu_register_bit_prop(X86CPU *cpu, { BitProperty *fp; ObjectProperty *op; - uint32_t mask = (1UL << bitnr); + uint64_t mask = (1ULL << bitnr); op = object_property_find(OBJECT(cpu), prop_name, NULL); if (op) { @@ -5668,7 +5929,7 @@ static void x86_cpu_initfn(Object *obj) for (w = 0; w < FEATURE_WORDS; w++) { int bitnr; - for (bitnr = 0; bitnr < 32; bitnr++) { + for (bitnr = 0; bitnr < 64; bitnr++) { x86_cpu_register_feature_bit_props(cpu, w, bitnr); } } @@ -5984,7 +6245,7 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) #ifndef CONFIG_USER_ONLY cc->asidx_from_attrs = x86_asidx_from_attrs; cc->get_memory_mapping = x86_cpu_get_memory_mapping; - cc->get_phys_page_debug = x86_cpu_get_phys_page_debug; + cc->get_phys_page_attrs_debug = x86_cpu_get_phys_page_attrs_debug; cc->write_elf64_note = x86_cpu_write_elf64_note; cc->write_elf64_qemunote = x86_cpu_write_elf64_qemunote; cc->write_elf32_note = x86_cpu_write_elf32_note; diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 5f6e3a029a..eaa5395aa5 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -452,6 +452,25 @@ typedef enum X86Seg { #define MSR_IA32_BNDCFGS 0x00000d90 #define MSR_IA32_XSS 0x00000da0 +#define MSR_IA32_VMX_BASIC 0x00000480 +#define MSR_IA32_VMX_PINBASED_CTLS 0x00000481 +#define MSR_IA32_VMX_PROCBASED_CTLS 0x00000482 +#define MSR_IA32_VMX_EXIT_CTLS 0x00000483 +#define MSR_IA32_VMX_ENTRY_CTLS 0x00000484 +#define MSR_IA32_VMX_MISC 0x00000485 +#define MSR_IA32_VMX_CR0_FIXED0 0x00000486 +#define MSR_IA32_VMX_CR0_FIXED1 0x00000487 +#define MSR_IA32_VMX_CR4_FIXED0 0x00000488 +#define MSR_IA32_VMX_CR4_FIXED1 0x00000489 +#define MSR_IA32_VMX_VMCS_ENUM 0x0000048a +#define MSR_IA32_VMX_PROCBASED_CTLS2 0x0000048b +#define MSR_IA32_VMX_EPT_VPID_CAP 0x0000048c +#define MSR_IA32_VMX_TRUE_PINBASED_CTLS 0x0000048d +#define MSR_IA32_VMX_TRUE_PROCBASED_CTLS 0x0000048e +#define MSR_IA32_VMX_TRUE_EXIT_CTLS 0x0000048f +#define MSR_IA32_VMX_TRUE_ENTRY_CTLS 0x00000490 +#define MSR_IA32_VMX_VMFUNC 0x00000491 + #define XSTATE_FP_BIT 0 #define XSTATE_SSE_BIT 1 #define XSTATE_YMM_BIT 2 @@ -499,10 +518,19 @@ typedef enum FeatureWord { FEAT_XSAVE_COMP_HI, /* CPUID[EAX=0xd,ECX=0].EDX */ FEAT_ARCH_CAPABILITIES, FEAT_CORE_CAPABILITY, + FEAT_VMX_PROCBASED_CTLS, + FEAT_VMX_SECONDARY_CTLS, + FEAT_VMX_PINBASED_CTLS, + FEAT_VMX_EXIT_CTLS, + FEAT_VMX_ENTRY_CTLS, + FEAT_VMX_MISC, + FEAT_VMX_EPT_VPID_CAPS, + FEAT_VMX_BASIC, + FEAT_VMX_VMFUNC, FEATURE_WORDS, } FeatureWord; -typedef uint32_t FeatureWordArray[FEATURE_WORDS]; +typedef uint64_t FeatureWordArray[FEATURE_WORDS]; /* cpuid_features bits */ #define CPUID_FP87 (1U << 0) @@ -695,6 +723,8 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; #define CPUID_7_1_EAX_AVX512_BF16 (1U << 5) /* AVX512 BFloat16 Instruction */ +#define CPUID_8000_0008_EBX_CLZERO (1U << 0) /* CLZERO instruction */ +#define CPUID_8000_0008_EBX_XSAVEERPTR (1U << 2) /* Always save/restore FP error pointers */ #define CPUID_8000_0008_EBX_WBNOINVD (1U << 9) /* Write back and do not invalidate cache */ #define CPUID_8000_0008_EBX_IBPB (1U << 12) /* Indirect Branch Prediction Barrier */ @@ -750,6 +780,117 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; #define MSR_CORE_CAP_SPLIT_LOCK_DETECT (1U << 5) +/* VMX MSR features */ +#define MSR_VMX_BASIC_VMCS_REVISION_MASK 0x7FFFFFFFull +#define MSR_VMX_BASIC_VMXON_REGION_SIZE_MASK (0x00001FFFull << 32) +#define MSR_VMX_BASIC_VMCS_MEM_TYPE_MASK (0x003C0000ull << 32) +#define MSR_VMX_BASIC_DUAL_MONITOR (1ULL << 49) +#define MSR_VMX_BASIC_INS_OUTS (1ULL << 54) +#define MSR_VMX_BASIC_TRUE_CTLS (1ULL << 55) + +#define MSR_VMX_MISC_PREEMPTION_TIMER_SHIFT_MASK 0x1Full +#define MSR_VMX_MISC_STORE_LMA (1ULL << 5) +#define MSR_VMX_MISC_ACTIVITY_HLT (1ULL << 6) +#define MSR_VMX_MISC_ACTIVITY_SHUTDOWN (1ULL << 7) +#define MSR_VMX_MISC_ACTIVITY_WAIT_SIPI (1ULL << 8) +#define MSR_VMX_MISC_MAX_MSR_LIST_SIZE_MASK 0x0E000000ull +#define MSR_VMX_MISC_VMWRITE_VMEXIT (1ULL << 29) +#define MSR_VMX_MISC_ZERO_LEN_INJECT (1ULL << 30) + +#define MSR_VMX_EPT_EXECONLY (1ULL << 0) +#define MSR_VMX_EPT_PAGE_WALK_LENGTH_4 (1ULL << 6) +#define MSR_VMX_EPT_PAGE_WALK_LENGTH_5 (1ULL << 7) +#define MSR_VMX_EPT_UC (1ULL << 8) +#define MSR_VMX_EPT_WB (1ULL << 14) +#define MSR_VMX_EPT_2MB (1ULL << 16) +#define MSR_VMX_EPT_1GB (1ULL << 17) +#define MSR_VMX_EPT_INVEPT (1ULL << 20) +#define MSR_VMX_EPT_AD_BITS (1ULL << 21) +#define MSR_VMX_EPT_ADVANCED_VMEXIT_INFO (1ULL << 22) +#define MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT (1ULL << 25) +#define MSR_VMX_EPT_INVEPT_ALL_CONTEXT (1ULL << 26) +#define MSR_VMX_EPT_INVVPID (1ULL << 32) +#define MSR_VMX_EPT_INVVPID_SINGLE_ADDR (1ULL << 40) +#define MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT (1ULL << 41) +#define MSR_VMX_EPT_INVVPID_ALL_CONTEXT (1ULL << 42) +#define MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS (1ULL << 43) + +#define MSR_VMX_VMFUNC_EPT_SWITCHING (1ULL << 0) + + +/* VMX controls */ +#define VMX_CPU_BASED_VIRTUAL_INTR_PENDING 0x00000004 +#define VMX_CPU_BASED_USE_TSC_OFFSETING 0x00000008 +#define VMX_CPU_BASED_HLT_EXITING 0x00000080 +#define VMX_CPU_BASED_INVLPG_EXITING 0x00000200 +#define VMX_CPU_BASED_MWAIT_EXITING 0x00000400 +#define VMX_CPU_BASED_RDPMC_EXITING 0x00000800 +#define VMX_CPU_BASED_RDTSC_EXITING 0x00001000 +#define VMX_CPU_BASED_CR3_LOAD_EXITING 0x00008000 +#define VMX_CPU_BASED_CR3_STORE_EXITING 0x00010000 +#define VMX_CPU_BASED_CR8_LOAD_EXITING 0x00080000 +#define VMX_CPU_BASED_CR8_STORE_EXITING 0x00100000 +#define VMX_CPU_BASED_TPR_SHADOW 0x00200000 +#define VMX_CPU_BASED_VIRTUAL_NMI_PENDING 0x00400000 +#define VMX_CPU_BASED_MOV_DR_EXITING 0x00800000 +#define VMX_CPU_BASED_UNCOND_IO_EXITING 0x01000000 +#define VMX_CPU_BASED_USE_IO_BITMAPS 0x02000000 +#define VMX_CPU_BASED_MONITOR_TRAP_FLAG 0x08000000 +#define VMX_CPU_BASED_USE_MSR_BITMAPS 0x10000000 +#define VMX_CPU_BASED_MONITOR_EXITING 0x20000000 +#define VMX_CPU_BASED_PAUSE_EXITING 0x40000000 +#define VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS 0x80000000 + +#define VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001 +#define VMX_SECONDARY_EXEC_ENABLE_EPT 0x00000002 +#define VMX_SECONDARY_EXEC_DESC 0x00000004 +#define VMX_SECONDARY_EXEC_RDTSCP 0x00000008 +#define VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE 0x00000010 +#define VMX_SECONDARY_EXEC_ENABLE_VPID 0x00000020 +#define VMX_SECONDARY_EXEC_WBINVD_EXITING 0x00000040 +#define VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST 0x00000080 +#define VMX_SECONDARY_EXEC_APIC_REGISTER_VIRT 0x00000100 +#define VMX_SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY 0x00000200 +#define VMX_SECONDARY_EXEC_PAUSE_LOOP_EXITING 0x00000400 +#define VMX_SECONDARY_EXEC_RDRAND_EXITING 0x00000800 +#define VMX_SECONDARY_EXEC_ENABLE_INVPCID 0x00001000 +#define VMX_SECONDARY_EXEC_ENABLE_VMFUNC 0x00002000 +#define VMX_SECONDARY_EXEC_SHADOW_VMCS 0x00004000 +#define VMX_SECONDARY_EXEC_ENCLS_EXITING 0x00008000 +#define VMX_SECONDARY_EXEC_RDSEED_EXITING 0x00010000 +#define VMX_SECONDARY_EXEC_ENABLE_PML 0x00020000 +#define VMX_SECONDARY_EXEC_XSAVES 0x00100000 + +#define VMX_PIN_BASED_EXT_INTR_MASK 0x00000001 +#define VMX_PIN_BASED_NMI_EXITING 0x00000008 +#define VMX_PIN_BASED_VIRTUAL_NMIS 0x00000020 +#define VMX_PIN_BASED_VMX_PREEMPTION_TIMER 0x00000040 +#define VMX_PIN_BASED_POSTED_INTR 0x00000080 + +#define VMX_VM_EXIT_SAVE_DEBUG_CONTROLS 0x00000004 +#define VMX_VM_EXIT_HOST_ADDR_SPACE_SIZE 0x00000200 +#define VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL 0x00001000 +#define VMX_VM_EXIT_ACK_INTR_ON_EXIT 0x00008000 +#define VMX_VM_EXIT_SAVE_IA32_PAT 0x00040000 +#define VMX_VM_EXIT_LOAD_IA32_PAT 0x00080000 +#define VMX_VM_EXIT_SAVE_IA32_EFER 0x00100000 +#define VMX_VM_EXIT_LOAD_IA32_EFER 0x00200000 +#define VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER 0x00400000 +#define VMX_VM_EXIT_CLEAR_BNDCFGS 0x00800000 +#define VMX_VM_EXIT_PT_CONCEAL_PIP 0x01000000 +#define VMX_VM_EXIT_CLEAR_IA32_RTIT_CTL 0x02000000 + +#define VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS 0x00000004 +#define VMX_VM_ENTRY_IA32E_MODE 0x00000200 +#define VMX_VM_ENTRY_SMM 0x00000400 +#define VMX_VM_ENTRY_DEACT_DUAL_MONITOR 0x00000800 +#define VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL 0x00002000 +#define VMX_VM_ENTRY_LOAD_IA32_PAT 0x00004000 +#define VMX_VM_ENTRY_LOAD_IA32_EFER 0x00008000 +#define VMX_VM_ENTRY_LOAD_BNDCFGS 0x00010000 +#define VMX_VM_ENTRY_PT_CONCEAL_PIP 0x00020000 +#define VMX_VM_ENTRY_LOAD_IA32_RTIT_CTL 0x00040000 + /* Supported Hyper-V Enlightenments */ #define HYPERV_FEAT_RELAXED 0 #define HYPERV_FEAT_VAPIC 1 @@ -1549,7 +1690,8 @@ void x86_cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, void x86_cpu_dump_state(CPUState *cs, FILE *f, int flags); -hwaddr x86_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +hwaddr x86_cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr, + MemTxAttrs *attrs); int x86_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); int x86_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); diff --git a/target/i386/helper.c b/target/i386/helper.c index 0fa51be646..c3a6e4fabe 100644 --- a/target/i386/helper.c +++ b/target/i386/helper.c @@ -715,7 +715,8 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4) } #if !defined(CONFIG_USER_ONLY) -hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) +hwaddr x86_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr, + MemTxAttrs *attrs) { X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; @@ -725,6 +726,8 @@ hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) uint32_t page_offset; int page_size; + *attrs = cpu_get_mem_attrs(env); + a20_mask = x86_get_a20_mask(env); if (!(env->cr[0] & CR0_PG_MASK)) { pte = addr & a20_mask; diff --git a/target/i386/kvm.c b/target/i386/kvm.c index 92069099ab..11b9c854b5 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -100,6 +100,7 @@ static bool has_msr_virt_ssbd; static bool has_msr_smi_count; static bool has_msr_arch_capabs; static bool has_msr_core_capabs; +static bool has_msr_vmx_vmfunc; static uint32_t has_architectural_pmu_version; static uint32_t num_architectural_pmu_gp_counters; @@ -187,7 +188,7 @@ static int kvm_get_tsc(CPUState *cs) struct { struct kvm_msrs info; struct kvm_msr_entry entries[1]; - } msr_data; + } msr_data = {}; int ret; if (env->tsc_valid) { @@ -442,13 +443,14 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function, return ret; } -uint32_t kvm_arch_get_supported_msr_feature(KVMState *s, uint32_t index) +uint64_t kvm_arch_get_supported_msr_feature(KVMState *s, uint32_t index) { struct { struct kvm_msrs info; struct kvm_msr_entry entries[1]; - } msr_data; - uint32_t ret; + } msr_data = {}; + uint64_t value; + uint32_t ret, can_be_one, must_be_one; if (kvm_feature_msrs == NULL) { /* Host doesn't support feature MSRs */ return 0; @@ -474,7 +476,42 @@ uint32_t kvm_arch_get_supported_msr_feature(KVMState *s, uint32_t index) exit(1); } - return msr_data.entries[0].data; + value = msr_data.entries[0].data; + switch (index) { + case MSR_IA32_VMX_PROCBASED_CTLS2: + /* KVM forgot to add these bits for some time, do this ourselves. */ + if (kvm_arch_get_supported_cpuid(s, 0xD, 1, R_ECX) & CPUID_XSAVE_XSAVES) { + value |= (uint64_t)VMX_SECONDARY_EXEC_XSAVES << 32; + } + if (kvm_arch_get_supported_cpuid(s, 1, 0, R_ECX) & CPUID_EXT_RDRAND) { + value |= (uint64_t)VMX_SECONDARY_EXEC_RDRAND_EXITING << 32; + } + if (kvm_arch_get_supported_cpuid(s, 7, 0, R_EBX) & CPUID_7_0_EBX_INVPCID) { + value |= (uint64_t)VMX_SECONDARY_EXEC_ENABLE_INVPCID << 32; + } + if (kvm_arch_get_supported_cpuid(s, 7, 0, R_EBX) & CPUID_7_0_EBX_RDSEED) { + value |= (uint64_t)VMX_SECONDARY_EXEC_RDSEED_EXITING << 32; + } + if (kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_EDX) & CPUID_EXT2_RDTSCP) { + value |= (uint64_t)VMX_SECONDARY_EXEC_RDTSCP << 32; + } + /* fall through */ + case MSR_IA32_VMX_TRUE_PINBASED_CTLS: + case MSR_IA32_VMX_TRUE_PROCBASED_CTLS: + case MSR_IA32_VMX_TRUE_ENTRY_CTLS: + case MSR_IA32_VMX_TRUE_EXIT_CTLS: + /* + * Return true for bits that can be one, but do not have to be one. + * The SDM tells us which bits could have a "must be one" setting, + * so we can do the opposite transformation in make_vmx_msr_value. + */ + must_be_one = (uint32_t)value; + can_be_one = (uint32_t)(value >> 32); + return can_be_one & ~must_be_one; + + default: + return value; + } } @@ -1939,6 +1976,9 @@ static int kvm_get_supported_msrs(KVMState *s) case MSR_IA32_CORE_CAPABILITY: has_msr_core_capabs = true; break; + case MSR_IA32_VMX_VMFUNC: + has_msr_vmx_vmfunc = true; + break; } } } @@ -2413,6 +2453,132 @@ static int kvm_put_msr_feature_control(X86CPU *cpu) return 0; } +static uint64_t make_vmx_msr_value(uint32_t index, uint32_t features) +{ + uint32_t default1, can_be_one, can_be_zero; + uint32_t must_be_one; + + switch (index) { + case MSR_IA32_VMX_TRUE_PINBASED_CTLS: + default1 = 0x00000016; + break; + case MSR_IA32_VMX_TRUE_PROCBASED_CTLS: + default1 = 0x0401e172; + break; + case MSR_IA32_VMX_TRUE_ENTRY_CTLS: + default1 = 0x000011ff; + break; + case MSR_IA32_VMX_TRUE_EXIT_CTLS: + default1 = 0x00036dff; + break; + case MSR_IA32_VMX_PROCBASED_CTLS2: + default1 = 0; + break; + default: + abort(); + } + + /* If a feature bit is set, the control can be either set or clear. + * Otherwise the value is limited to either 0 or 1 by default1. + */ + can_be_one = features | default1; + can_be_zero = features | ~default1; + must_be_one = ~can_be_zero; + + /* + * Bit 0:31 -> 0 if the control bit can be zero (i.e. 1 if it must be one). + * Bit 32:63 -> 1 if the control bit can be one. + */ + return must_be_one | (((uint64_t)can_be_one) << 32); +} + +#define VMCS12_MAX_FIELD_INDEX (0x17) + +static void kvm_msr_entry_add_vmx(X86CPU *cpu, FeatureWordArray f) +{ + uint64_t kvm_vmx_basic = + kvm_arch_get_supported_msr_feature(kvm_state, + MSR_IA32_VMX_BASIC); + uint64_t kvm_vmx_misc = + kvm_arch_get_supported_msr_feature(kvm_state, + MSR_IA32_VMX_MISC); + uint64_t kvm_vmx_ept_vpid = + kvm_arch_get_supported_msr_feature(kvm_state, + MSR_IA32_VMX_EPT_VPID_CAP); + + /* + * If the guest is 64-bit, a value of 1 is allowed for the host address + * space size vmexit control. + */ + uint64_t fixed_vmx_exit = f[FEAT_8000_0001_EDX] & CPUID_EXT2_LM + ? (uint64_t)VMX_VM_EXIT_HOST_ADDR_SPACE_SIZE << 32 : 0; + + /* + * Bits 0-30, 32-44 and 50-53 come from the host. KVM should + * not change them for backwards compatibility. + */ + uint64_t fixed_vmx_basic = kvm_vmx_basic & + (MSR_VMX_BASIC_VMCS_REVISION_MASK | + MSR_VMX_BASIC_VMXON_REGION_SIZE_MASK | + MSR_VMX_BASIC_VMCS_MEM_TYPE_MASK); + + /* + * Same for bits 0-4 and 25-27. Bits 16-24 (CR3 target count) can + * change in the future but are always zero for now, clear them to be + * future proof. Bits 32-63 in theory could change, though KVM does + * not support dual-monitor treatment and probably never will; mask + * them out as well. + */ + uint64_t fixed_vmx_misc = kvm_vmx_misc & + (MSR_VMX_MISC_PREEMPTION_TIMER_SHIFT_MASK | + MSR_VMX_MISC_MAX_MSR_LIST_SIZE_MASK); + + /* + * EPT memory types should not change either, so we do not bother + * adding features for them. + */ + uint64_t fixed_vmx_ept_mask = + (f[FEAT_VMX_SECONDARY_CTLS] & VMX_SECONDARY_EXEC_ENABLE_EPT ? + MSR_VMX_EPT_UC | MSR_VMX_EPT_WB : 0); + uint64_t fixed_vmx_ept_vpid = kvm_vmx_ept_vpid & fixed_vmx_ept_mask; + + kvm_msr_entry_add(cpu, MSR_IA32_VMX_TRUE_PROCBASED_CTLS, + make_vmx_msr_value(MSR_IA32_VMX_TRUE_PROCBASED_CTLS, + f[FEAT_VMX_PROCBASED_CTLS])); + kvm_msr_entry_add(cpu, MSR_IA32_VMX_TRUE_PINBASED_CTLS, + make_vmx_msr_value(MSR_IA32_VMX_TRUE_PINBASED_CTLS, + f[FEAT_VMX_PINBASED_CTLS])); + kvm_msr_entry_add(cpu, MSR_IA32_VMX_TRUE_EXIT_CTLS, + make_vmx_msr_value(MSR_IA32_VMX_TRUE_EXIT_CTLS, + f[FEAT_VMX_EXIT_CTLS]) | fixed_vmx_exit); + kvm_msr_entry_add(cpu, MSR_IA32_VMX_TRUE_ENTRY_CTLS, + make_vmx_msr_value(MSR_IA32_VMX_TRUE_ENTRY_CTLS, + f[FEAT_VMX_ENTRY_CTLS])); + kvm_msr_entry_add(cpu, MSR_IA32_VMX_PROCBASED_CTLS2, + make_vmx_msr_value(MSR_IA32_VMX_PROCBASED_CTLS2, + f[FEAT_VMX_SECONDARY_CTLS])); + kvm_msr_entry_add(cpu, MSR_IA32_VMX_EPT_VPID_CAP, + f[FEAT_VMX_EPT_VPID_CAPS] | fixed_vmx_ept_vpid); + kvm_msr_entry_add(cpu, MSR_IA32_VMX_BASIC, + f[FEAT_VMX_BASIC] | fixed_vmx_basic); + kvm_msr_entry_add(cpu, MSR_IA32_VMX_MISC, + f[FEAT_VMX_MISC] | fixed_vmx_misc); + if (has_msr_vmx_vmfunc) { + kvm_msr_entry_add(cpu, MSR_IA32_VMX_VMFUNC, f[FEAT_VMX_VMFUNC]); + } + + /* + * Just to be safe, write these with constant values. The CRn_FIXED1 + * MSRs are generated by KVM based on the vCPU's CPUID. + */ + kvm_msr_entry_add(cpu, MSR_IA32_VMX_CR0_FIXED0, + CR0_PE_MASK | CR0_PG_MASK | CR0_NE_MASK); + kvm_msr_entry_add(cpu, MSR_IA32_VMX_CR4_FIXED0, + CR4_VMXE_MASK); + kvm_msr_entry_add(cpu, MSR_IA32_VMX_VMCS_ENUM, + VMCS12_MAX_FIELD_INDEX << 1); +} + static int kvm_put_msrs(X86CPU *cpu, int level) { CPUX86State *env = &cpu->env; @@ -2657,7 +2823,16 @@ static int kvm_put_msrs(X86CPU *cpu, int level) /* Note: MSR_IA32_FEATURE_CONTROL is written separately, see * kvm_put_msr_feature_control. */ + + /* + * Older kernels do not include VMX MSRs in KVM_GET_MSR_INDEX_LIST, but + * all kernels with MSR features should have them. + */ + if (kvm_feature_msrs && cpu_has_vmx(env)) { + kvm_msr_entry_add_vmx(cpu, env->features); + } } + if (env->mcg_cap) { int i; diff --git a/target/i386/whpx-all.c b/target/i386/whpx-all.c index 0c15241ae4..def0c28480 100644 --- a/target/i386/whpx-all.c +++ b/target/i386/whpx-all.c @@ -18,6 +18,7 @@ #include "sysemu/cpus.h" #include "sysemu/runstate.h" #include "qemu/main-loop.h" +#include "hw/boards.h" #include "qemu/error-report.h" #include "qapi/error.h" #include "migration/blocker.h" diff --git a/target/mips/helper.h b/target/mips/helper.h index 51f0e1c183..d615c83c54 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -777,6 +777,123 @@ DEF_HELPER_FLAGS_3(wrdsp, 0, void, tl, tl, env) DEF_HELPER_FLAGS_2(rddsp, 0, tl, tl, env) /* MIPS SIMD Architecture */ + +DEF_HELPER_3(msa_nloc_b, void, env, i32, i32) +DEF_HELPER_3(msa_nloc_h, void, env, i32, i32) +DEF_HELPER_3(msa_nloc_w, void, env, i32, i32) +DEF_HELPER_3(msa_nloc_d, void, env, i32, i32) + +DEF_HELPER_3(msa_nlzc_b, void, env, i32, i32) +DEF_HELPER_3(msa_nlzc_h, void, env, i32, i32) +DEF_HELPER_3(msa_nlzc_w, void, env, i32, i32) +DEF_HELPER_3(msa_nlzc_d, void, env, i32, i32) + +DEF_HELPER_3(msa_pcnt_b, void, env, i32, i32) +DEF_HELPER_3(msa_pcnt_h, void, env, i32, i32) +DEF_HELPER_3(msa_pcnt_w, void, env, i32, i32) +DEF_HELPER_3(msa_pcnt_d, void, env, i32, i32) + +DEF_HELPER_4(msa_binsl_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_binsl_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_binsl_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_binsl_d, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_binsr_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_binsr_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_binsr_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_binsr_d, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_bmnz_v, void, env, i32, i32, i32) +DEF_HELPER_4(msa_bmz_v, void, env, i32, i32, i32) +DEF_HELPER_4(msa_bsel_v, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_bclr_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_bclr_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_bclr_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_bclr_d, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_bneg_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_bneg_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_bneg_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_bneg_d, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_bset_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_bset_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_bset_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_bset_d, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_ave_s_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_ave_s_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_ave_s_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_ave_s_d, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_ave_u_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_ave_u_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_ave_u_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_ave_u_d, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_aver_s_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_aver_s_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_aver_s_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_aver_s_d, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_aver_u_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_aver_u_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_aver_u_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_aver_u_d, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_ceq_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_ceq_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_ceq_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_ceq_d, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_cle_s_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_cle_s_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_cle_s_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_cle_s_d, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_cle_u_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_cle_u_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_cle_u_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_cle_u_d, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_clt_s_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_clt_s_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_clt_s_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_clt_s_d, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_clt_u_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_clt_u_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_clt_u_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_clt_u_d, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_div_s_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_div_s_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_div_s_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_div_s_d, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_div_u_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_div_u_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_div_u_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_div_u_d, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_mod_u_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_mod_u_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_mod_u_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_mod_u_d, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_mod_s_b, void, env, i32, i32, i32) +DEF_HELPER_4(msa_mod_s_h, void, env, i32, i32, i32) +DEF_HELPER_4(msa_mod_s_w, void, env, i32, i32, i32) +DEF_HELPER_4(msa_mod_s_d, void, env, i32, i32, i32) + +DEF_HELPER_4(msa_and_v, void, env, i32, i32, i32) +DEF_HELPER_4(msa_nor_v, void, env, i32, i32, i32) +DEF_HELPER_4(msa_or_v, void, env, i32, i32, i32) +DEF_HELPER_4(msa_xor_v, void, env, i32, i32, i32) + +DEF_HELPER_3(msa_move_v, void, env, i32, i32) + DEF_HELPER_4(msa_andi_b, void, env, i32, i32, i32) DEF_HELPER_4(msa_ori_b, void, env, i32, i32, i32) DEF_HELPER_4(msa_nori_b, void, env, i32, i32, i32) @@ -815,9 +932,6 @@ DEF_HELPER_5(msa_srlri_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_sll_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_sra_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_srl_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_bclr_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_bset_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_bneg_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_binsl_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_binsr_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_addv_df, void, env, i32, i32, i32, i32) @@ -828,19 +942,10 @@ DEF_HELPER_5(msa_min_s_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_min_u_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_max_a_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_min_a_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_ceq_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_clt_s_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_clt_u_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_cle_s_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_cle_u_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_add_a_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_adds_a_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_adds_s_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_adds_u_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_ave_s_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_ave_u_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_aver_s_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_aver_u_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_subs_s_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_subs_u_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_subsus_u_df, void, env, i32, i32, i32, i32) @@ -850,10 +955,6 @@ DEF_HELPER_5(msa_asub_u_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_mulv_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_maddv_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_msubv_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_div_s_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_div_u_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_mod_s_df, void, env, i32, i32, i32, i32) -DEF_HELPER_5(msa_mod_u_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_dotp_s_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_dotp_u_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_dpadd_s_df, void, env, i32, i32, i32, i32) @@ -882,7 +983,6 @@ DEF_HELPER_5(msa_splati_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_insve_df, void, env, i32, i32, i32, i32) DEF_HELPER_3(msa_ctcmsa, void, env, tl, i32) DEF_HELPER_2(msa_cfcmsa, tl, env, i32) -DEF_HELPER_3(msa_move_v, void, env, i32, i32) DEF_HELPER_5(msa_fcaf_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_fcun_df, void, env, i32, i32, i32, i32) @@ -926,17 +1026,7 @@ DEF_HELPER_5(msa_mulr_q_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_maddr_q_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_msubr_q_df, void, env, i32, i32, i32, i32) -DEF_HELPER_4(msa_and_v, void, env, i32, i32, i32) -DEF_HELPER_4(msa_or_v, void, env, i32, i32, i32) -DEF_HELPER_4(msa_nor_v, void, env, i32, i32, i32) -DEF_HELPER_4(msa_xor_v, void, env, i32, i32, i32) -DEF_HELPER_4(msa_bmnz_v, void, env, i32, i32, i32) -DEF_HELPER_4(msa_bmz_v, void, env, i32, i32, i32) -DEF_HELPER_4(msa_bsel_v, void, env, i32, i32, i32) DEF_HELPER_4(msa_fill_df, void, env, i32, i32, i32) -DEF_HELPER_4(msa_pcnt_df, void, env, i32, i32, i32) -DEF_HELPER_4(msa_nloc_df, void, env, i32, i32, i32) -DEF_HELPER_4(msa_nlzc_df, void, env, i32, i32, i32) DEF_HELPER_4(msa_copy_s_b, void, env, i32, i32, i32) DEF_HELPER_4(msa_copy_s_h, void, env, i32, i32, i32) diff --git a/target/mips/internal.h b/target/mips/internal.h index 685e8d67e9..3f435b5e63 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -1,4 +1,5 @@ -/* mips internal definitions and helpers +/* + * MIPS internal definitions and helpers * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. @@ -9,8 +10,10 @@ #include "fpu/softfloat-helpers.h" -/* MMU types, the first four entries have the same layout as the - CP0C0_MT field. */ +/* + * MMU types, the first four entries have the same layout as the + * CP0C0_MT field. + */ enum mips_mmu_types { MMU_TYPE_NONE, MMU_TYPE_R4000, @@ -160,9 +163,11 @@ static inline bool cpu_mips_hw_interrupts_enabled(CPUMIPSState *env) !(env->CP0_Status & (1 << CP0St_EXL)) && !(env->CP0_Status & (1 << CP0St_ERL)) && !(env->hflags & MIPS_HFLAG_DM) && - /* Note that the TCStatus IXMT field is initialized to zero, - and only MT capable cores can set it to one. So we don't - need to check for MT capabilities here. */ + /* + * Note that the TCStatus IXMT field is initialized to zero, + * and only MT capable cores can set it to one. So we don't + * need to check for MT capabilities here. + */ !(env->active_tc.CP0_TCStatus & (1 << CP0TCSt_IXMT)); } @@ -177,14 +182,18 @@ static inline bool cpu_mips_hw_interrupts_pending(CPUMIPSState *env) status = env->CP0_Status & CP0Ca_IP_mask; if (env->CP0_Config3 & (1 << CP0C3_VEIC)) { - /* A MIPS configured with a vectorizing external interrupt controller - will feed a vector into the Cause pending lines. The core treats - the status lines as a vector level, not as indiviual masks. */ + /* + * A MIPS configured with a vectorizing external interrupt controller + * will feed a vector into the Cause pending lines. The core treats + * the status lines as a vector level, not as indiviual masks. + */ r = pending > status; } else { - /* A MIPS configured with compatibility or VInt (Vectored Interrupts) - treats the pending lines as individual interrupt lines, the status - lines are individual masks. */ + /* + * A MIPS configured with compatibility or VInt (Vectored Interrupts) + * treats the pending lines as individual interrupt lines, the status + * lines are individual masks. + */ r = (pending & status) != 0; } return r; @@ -275,12 +284,14 @@ static inline int mips_vpe_active(CPUMIPSState *env) active = 0; } - /* Now verify that there are active thread contexts in the VPE. - - This assumes the CPU model will internally reschedule threads - if the active one goes to sleep. If there are no threads available - the active one will be in a sleeping state, and we can turn off - the entire VPE. */ + /* + * Now verify that there are active thread contexts in the VPE. + * + * This assumes the CPU model will internally reschedule threads + * if the active one goes to sleep. If there are no threads available + * the active one will be in a sleeping state, and we can turn off + * the entire VPE. + */ if (!(env->active_tc.CP0_TCStatus & (1 << CP0TCSt_A))) { /* TC is not activated. */ active = 0; @@ -326,7 +337,8 @@ static inline void compute_hflags(CPUMIPSState *env) if (!(env->CP0_Status & (1 << CP0St_EXL)) && !(env->CP0_Status & (1 << CP0St_ERL)) && !(env->hflags & MIPS_HFLAG_DM)) { - env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU; + env->hflags |= (env->CP0_Status >> CP0St_KSU) & + MIPS_HFLAG_KSU; } #if defined(TARGET_MIPS64) if ((env->insn_flags & ISA_MIPS3) && @@ -403,10 +415,12 @@ static inline void compute_hflags(CPUMIPSState *env) env->hflags |= MIPS_HFLAG_COP1X; } } else if (env->insn_flags & ISA_MIPS4) { - /* All supported MIPS IV CPUs use the XX (CU3) to enable - and disable the MIPS IV extensions to the MIPS III ISA. - Some other MIPS IV CPUs ignore the bit, so the check here - would be too restrictive for them. */ + /* + * All supported MIPS IV CPUs use the XX (CU3) to enable + * and disable the MIPS IV extensions to the MIPS III ISA. + * Some other MIPS IV CPUs ignore the bit, so the check here + * would be too restrictive for them. + */ if (env->CP0_Status & (1U << CP0St_CU3)) { env->hflags |= MIPS_HFLAG_COP1X; } diff --git a/target/mips/kvm_mips.h b/target/mips/kvm_mips.h index ae957f37f0..1e4014792d 100644 --- a/target/mips/kvm_mips.h +++ b/target/mips/kvm_mips.h @@ -7,7 +7,7 @@ * * Copyright (C) 2012-2014 Imagination Technologies Ltd. * Authors: Sanjay Lal <sanjayl@kymasys.com> -*/ + */ #ifndef KVM_MIPS_H #define KVM_MIPS_H diff --git a/target/mips/mips-defs.h b/target/mips/mips-defs.h index bbf056a548..a831bb4384 100644 --- a/target/mips/mips-defs.h +++ b/target/mips/mips-defs.h @@ -1,8 +1,11 @@ #ifndef QEMU_MIPS_DEFS_H #define QEMU_MIPS_DEFS_H -/* If we want to use host float regs... */ -//#define USE_HOST_FLOAT_REGS +/* + * If we want to use host float regs... + * + * #define USE_HOST_FLOAT_REGS + */ /* Real pages are variable size... */ #define MIPS_TLB_MAX 128 @@ -57,43 +60,46 @@ #define ASE_MXU 0x0200000000000000ULL /* MIPS CPU defines. */ -#define CPU_MIPS1 (ISA_MIPS1) -#define CPU_MIPS2 (CPU_MIPS1 | ISA_MIPS2) -#define CPU_MIPS3 (CPU_MIPS2 | ISA_MIPS3) -#define CPU_MIPS4 (CPU_MIPS3 | ISA_MIPS4) -#define CPU_VR54XX (CPU_MIPS4 | INSN_VR54XX) -#define CPU_R5900 (CPU_MIPS3 | INSN_R5900) -#define CPU_LOONGSON2E (CPU_MIPS3 | INSN_LOONGSON2E) -#define CPU_LOONGSON2F (CPU_MIPS3 | INSN_LOONGSON2F) +#define CPU_MIPS1 (ISA_MIPS1) +#define CPU_MIPS2 (CPU_MIPS1 | ISA_MIPS2) +#define CPU_MIPS3 (CPU_MIPS2 | ISA_MIPS3) +#define CPU_MIPS4 (CPU_MIPS3 | ISA_MIPS4) +#define CPU_VR54XX (CPU_MIPS4 | INSN_VR54XX) +#define CPU_R5900 (CPU_MIPS3 | INSN_R5900) +#define CPU_LOONGSON2E (CPU_MIPS3 | INSN_LOONGSON2E) +#define CPU_LOONGSON2F (CPU_MIPS3 | INSN_LOONGSON2F) -#define CPU_MIPS5 (CPU_MIPS4 | ISA_MIPS5) +#define CPU_MIPS5 (CPU_MIPS4 | ISA_MIPS5) /* MIPS Technologies "Release 1" */ -#define CPU_MIPS32 (CPU_MIPS2 | ISA_MIPS32) -#define CPU_MIPS64 (CPU_MIPS5 | CPU_MIPS32 | ISA_MIPS64) +#define CPU_MIPS32 (CPU_MIPS2 | ISA_MIPS32) +#define CPU_MIPS64 (CPU_MIPS5 | CPU_MIPS32 | ISA_MIPS64) /* MIPS Technologies "Release 2" */ -#define CPU_MIPS32R2 (CPU_MIPS32 | ISA_MIPS32R2) -#define CPU_MIPS64R2 (CPU_MIPS64 | CPU_MIPS32R2 | ISA_MIPS64R2) +#define CPU_MIPS32R2 (CPU_MIPS32 | ISA_MIPS32R2) +#define CPU_MIPS64R2 (CPU_MIPS64 | CPU_MIPS32R2 | ISA_MIPS64R2) /* MIPS Technologies "Release 3" */ -#define CPU_MIPS32R3 (CPU_MIPS32R2 | ISA_MIPS32R3) -#define CPU_MIPS64R3 (CPU_MIPS64R2 | CPU_MIPS32R3 | ISA_MIPS64R3) +#define CPU_MIPS32R3 (CPU_MIPS32R2 | ISA_MIPS32R3) +#define CPU_MIPS64R3 (CPU_MIPS64R2 | CPU_MIPS32R3 | ISA_MIPS64R3) /* MIPS Technologies "Release 5" */ -#define CPU_MIPS32R5 (CPU_MIPS32R3 | ISA_MIPS32R5) -#define CPU_MIPS64R5 (CPU_MIPS64R3 | CPU_MIPS32R5 | ISA_MIPS64R5) +#define CPU_MIPS32R5 (CPU_MIPS32R3 | ISA_MIPS32R5) +#define CPU_MIPS64R5 (CPU_MIPS64R3 | CPU_MIPS32R5 | ISA_MIPS64R5) /* MIPS Technologies "Release 6" */ -#define CPU_MIPS32R6 (CPU_MIPS32R5 | ISA_MIPS32R6) -#define CPU_MIPS64R6 (CPU_MIPS64R5 | CPU_MIPS32R6 | ISA_MIPS64R6) +#define CPU_MIPS32R6 (CPU_MIPS32R5 | ISA_MIPS32R6) +#define CPU_MIPS64R6 (CPU_MIPS64R5 | CPU_MIPS32R6 | ISA_MIPS64R6) /* Wave Computing: "nanoMIPS" */ -#define CPU_NANOMIPS32 (CPU_MIPS32R6 | ISA_NANOMIPS32) +#define CPU_NANOMIPS32 (CPU_MIPS32R6 | ISA_NANOMIPS32) -/* Strictly follow the architecture standard: - - Disallow "special" instruction handling for PMON/SPIM. - Note that we still maintain Count/Compare to match the host clock. */ -//#define MIPS_STRICT_STANDARD 1 +/* + * Strictly follow the architecture standard: + * - Disallow "special" instruction handling for PMON/SPIM. + * Note that we still maintain Count/Compare to match the host clock. + * + * #define MIPS_STRICT_STANDARD 1 + */ #endif /* QEMU_MIPS_DEFS_H */ diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c index f24061e2af..a2052baa57 100644 --- a/target/mips/msa_helper.c +++ b/target/mips/msa_helper.c @@ -65,7 +65,221 @@ * +---------------+----------------------------------------------------------+ */ -/* TODO: insert Bit Count group helpers here */ +static inline int64_t msa_nlzc_df(uint32_t df, int64_t arg) +{ + uint64_t x, y; + int n, c; + + x = UNSIGNED(arg, df); + n = DF_BITS(df); + c = DF_BITS(df) / 2; + + do { + y = x >> c; + if (y != 0) { + n = n - c; + x = y; + } + c = c >> 1; + } while (c != 0); + + return n - x; +} + +static inline int64_t msa_nloc_df(uint32_t df, int64_t arg) +{ + return msa_nlzc_df(df, UNSIGNED((~arg), df)); +} + +void helper_msa_nloc_b(CPUMIPSState *env, uint32_t wd, uint32_t ws) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + + pwd->b[0] = msa_nloc_df(DF_BYTE, pws->b[0]); + pwd->b[1] = msa_nloc_df(DF_BYTE, pws->b[1]); + pwd->b[2] = msa_nloc_df(DF_BYTE, pws->b[2]); + pwd->b[3] = msa_nloc_df(DF_BYTE, pws->b[3]); + pwd->b[4] = msa_nloc_df(DF_BYTE, pws->b[4]); + pwd->b[5] = msa_nloc_df(DF_BYTE, pws->b[5]); + pwd->b[6] = msa_nloc_df(DF_BYTE, pws->b[6]); + pwd->b[7] = msa_nloc_df(DF_BYTE, pws->b[7]); + pwd->b[8] = msa_nloc_df(DF_BYTE, pws->b[8]); + pwd->b[9] = msa_nloc_df(DF_BYTE, pws->b[9]); + pwd->b[10] = msa_nloc_df(DF_BYTE, pws->b[10]); + pwd->b[11] = msa_nloc_df(DF_BYTE, pws->b[11]); + pwd->b[12] = msa_nloc_df(DF_BYTE, pws->b[12]); + pwd->b[13] = msa_nloc_df(DF_BYTE, pws->b[13]); + pwd->b[14] = msa_nloc_df(DF_BYTE, pws->b[14]); + pwd->b[15] = msa_nloc_df(DF_BYTE, pws->b[15]); +} + +void helper_msa_nloc_h(CPUMIPSState *env, uint32_t wd, uint32_t ws) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + + pwd->h[0] = msa_nloc_df(DF_HALF, pws->h[0]); + pwd->h[1] = msa_nloc_df(DF_HALF, pws->h[1]); + pwd->h[2] = msa_nloc_df(DF_HALF, pws->h[2]); + pwd->h[3] = msa_nloc_df(DF_HALF, pws->h[3]); + pwd->h[4] = msa_nloc_df(DF_HALF, pws->h[4]); + pwd->h[5] = msa_nloc_df(DF_HALF, pws->h[5]); + pwd->h[6] = msa_nloc_df(DF_HALF, pws->h[6]); + pwd->h[7] = msa_nloc_df(DF_HALF, pws->h[7]); +} + +void helper_msa_nloc_w(CPUMIPSState *env, uint32_t wd, uint32_t ws) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + + pwd->w[0] = msa_nloc_df(DF_WORD, pws->w[0]); + pwd->w[1] = msa_nloc_df(DF_WORD, pws->w[1]); + pwd->w[2] = msa_nloc_df(DF_WORD, pws->w[2]); + pwd->w[3] = msa_nloc_df(DF_WORD, pws->w[3]); +} + +void helper_msa_nloc_d(CPUMIPSState *env, uint32_t wd, uint32_t ws) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + + pwd->d[0] = msa_nloc_df(DF_DOUBLE, pws->d[0]); + pwd->d[1] = msa_nloc_df(DF_DOUBLE, pws->d[1]); +} + +void helper_msa_nlzc_b(CPUMIPSState *env, uint32_t wd, uint32_t ws) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + + pwd->b[0] = msa_nlzc_df(DF_BYTE, pws->b[0]); + pwd->b[1] = msa_nlzc_df(DF_BYTE, pws->b[1]); + pwd->b[2] = msa_nlzc_df(DF_BYTE, pws->b[2]); + pwd->b[3] = msa_nlzc_df(DF_BYTE, pws->b[3]); + pwd->b[4] = msa_nlzc_df(DF_BYTE, pws->b[4]); + pwd->b[5] = msa_nlzc_df(DF_BYTE, pws->b[5]); + pwd->b[6] = msa_nlzc_df(DF_BYTE, pws->b[6]); + pwd->b[7] = msa_nlzc_df(DF_BYTE, pws->b[7]); + pwd->b[8] = msa_nlzc_df(DF_BYTE, pws->b[8]); + pwd->b[9] = msa_nlzc_df(DF_BYTE, pws->b[9]); + pwd->b[10] = msa_nlzc_df(DF_BYTE, pws->b[10]); + pwd->b[11] = msa_nlzc_df(DF_BYTE, pws->b[11]); + pwd->b[12] = msa_nlzc_df(DF_BYTE, pws->b[12]); + pwd->b[13] = msa_nlzc_df(DF_BYTE, pws->b[13]); + pwd->b[14] = msa_nlzc_df(DF_BYTE, pws->b[14]); + pwd->b[15] = msa_nlzc_df(DF_BYTE, pws->b[15]); +} + +void helper_msa_nlzc_h(CPUMIPSState *env, uint32_t wd, uint32_t ws) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + + pwd->h[0] = msa_nlzc_df(DF_HALF, pws->h[0]); + pwd->h[1] = msa_nlzc_df(DF_HALF, pws->h[1]); + pwd->h[2] = msa_nlzc_df(DF_HALF, pws->h[2]); + pwd->h[3] = msa_nlzc_df(DF_HALF, pws->h[3]); + pwd->h[4] = msa_nlzc_df(DF_HALF, pws->h[4]); + pwd->h[5] = msa_nlzc_df(DF_HALF, pws->h[5]); + pwd->h[6] = msa_nlzc_df(DF_HALF, pws->h[6]); + pwd->h[7] = msa_nlzc_df(DF_HALF, pws->h[7]); +} + +void helper_msa_nlzc_w(CPUMIPSState *env, uint32_t wd, uint32_t ws) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + + pwd->w[0] = msa_nlzc_df(DF_WORD, pws->w[0]); + pwd->w[1] = msa_nlzc_df(DF_WORD, pws->w[1]); + pwd->w[2] = msa_nlzc_df(DF_WORD, pws->w[2]); + pwd->w[3] = msa_nlzc_df(DF_WORD, pws->w[3]); +} + +void helper_msa_nlzc_d(CPUMIPSState *env, uint32_t wd, uint32_t ws) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + + pwd->d[0] = msa_nlzc_df(DF_DOUBLE, pws->d[0]); + pwd->d[1] = msa_nlzc_df(DF_DOUBLE, pws->d[1]); +} + +static inline int64_t msa_pcnt_df(uint32_t df, int64_t arg) +{ + uint64_t x; + + x = UNSIGNED(arg, df); + + x = (x & 0x5555555555555555ULL) + ((x >> 1) & 0x5555555555555555ULL); + x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL); + x = (x & 0x0F0F0F0F0F0F0F0FULL) + ((x >> 4) & 0x0F0F0F0F0F0F0F0FULL); + x = (x & 0x00FF00FF00FF00FFULL) + ((x >> 8) & 0x00FF00FF00FF00FFULL); + x = (x & 0x0000FFFF0000FFFFULL) + ((x >> 16) & 0x0000FFFF0000FFFFULL); + x = (x & 0x00000000FFFFFFFFULL) + ((x >> 32)); + + return x; +} + +void helper_msa_pcnt_b(CPUMIPSState *env, uint32_t wd, uint32_t ws) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + + pwd->b[0] = msa_pcnt_df(DF_BYTE, pws->b[0]); + pwd->b[1] = msa_pcnt_df(DF_BYTE, pws->b[1]); + pwd->b[2] = msa_pcnt_df(DF_BYTE, pws->b[2]); + pwd->b[3] = msa_pcnt_df(DF_BYTE, pws->b[3]); + pwd->b[4] = msa_pcnt_df(DF_BYTE, pws->b[4]); + pwd->b[5] = msa_pcnt_df(DF_BYTE, pws->b[5]); + pwd->b[6] = msa_pcnt_df(DF_BYTE, pws->b[6]); + pwd->b[7] = msa_pcnt_df(DF_BYTE, pws->b[7]); + pwd->b[8] = msa_pcnt_df(DF_BYTE, pws->b[8]); + pwd->b[9] = msa_pcnt_df(DF_BYTE, pws->b[9]); + pwd->b[10] = msa_pcnt_df(DF_BYTE, pws->b[10]); + pwd->b[11] = msa_pcnt_df(DF_BYTE, pws->b[11]); + pwd->b[12] = msa_pcnt_df(DF_BYTE, pws->b[12]); + pwd->b[13] = msa_pcnt_df(DF_BYTE, pws->b[13]); + pwd->b[14] = msa_pcnt_df(DF_BYTE, pws->b[14]); + pwd->b[15] = msa_pcnt_df(DF_BYTE, pws->b[15]); +} + +void helper_msa_pcnt_h(CPUMIPSState *env, uint32_t wd, uint32_t ws) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + + pwd->h[0] = msa_pcnt_df(DF_HALF, pws->h[0]); + pwd->h[1] = msa_pcnt_df(DF_HALF, pws->h[1]); + pwd->h[2] = msa_pcnt_df(DF_HALF, pws->h[2]); + pwd->h[3] = msa_pcnt_df(DF_HALF, pws->h[3]); + pwd->h[4] = msa_pcnt_df(DF_HALF, pws->h[4]); + pwd->h[5] = msa_pcnt_df(DF_HALF, pws->h[5]); + pwd->h[6] = msa_pcnt_df(DF_HALF, pws->h[6]); + pwd->h[7] = msa_pcnt_df(DF_HALF, pws->h[7]); +} + +void helper_msa_pcnt_w(CPUMIPSState *env, uint32_t wd, uint32_t ws) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + + pwd->w[0] = msa_pcnt_df(DF_WORD, pws->w[0]); + pwd->w[1] = msa_pcnt_df(DF_WORD, pws->w[1]); + pwd->w[2] = msa_pcnt_df(DF_WORD, pws->w[2]); + pwd->w[3] = msa_pcnt_df(DF_WORD, pws->w[3]); +} + +void helper_msa_pcnt_d(CPUMIPSState *env, uint32_t wd, uint32_t ws) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + + pwd->d[0] = msa_pcnt_df(DF_DOUBLE, pws->d[0]); + pwd->d[1] = msa_pcnt_df(DF_DOUBLE, pws->d[1]); +} /* @@ -87,7 +301,206 @@ * +---------------+----------------------------------------------------------+ */ -/* TODO: insert Bit Move group helpers here */ +/* Data format bit position and unsigned values */ +#define BIT_POSITION(x, df) ((uint64_t)(x) % DF_BITS(df)) + +static inline int64_t msa_binsl_df(uint32_t df, + int64_t dest, int64_t arg1, int64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t u_dest = UNSIGNED(dest, df); + int32_t sh_d = BIT_POSITION(arg2, df) + 1; + int32_t sh_a = DF_BITS(df) - sh_d; + if (sh_d == DF_BITS(df)) { + return u_arg1; + } else { + return UNSIGNED(UNSIGNED(u_dest << sh_d, df) >> sh_d, df) | + UNSIGNED(UNSIGNED(u_arg1 >> sh_a, df) << sh_a, df); + } +} + +void helper_msa_binsl_b(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_binsl_df(DF_BYTE, pwd->b[0], pws->b[0], pwt->b[0]); + pwd->b[1] = msa_binsl_df(DF_BYTE, pwd->b[1], pws->b[1], pwt->b[1]); + pwd->b[2] = msa_binsl_df(DF_BYTE, pwd->b[2], pws->b[2], pwt->b[2]); + pwd->b[3] = msa_binsl_df(DF_BYTE, pwd->b[3], pws->b[3], pwt->b[3]); + pwd->b[4] = msa_binsl_df(DF_BYTE, pwd->b[4], pws->b[4], pwt->b[4]); + pwd->b[5] = msa_binsl_df(DF_BYTE, pwd->b[5], pws->b[5], pwt->b[5]); + pwd->b[6] = msa_binsl_df(DF_BYTE, pwd->b[6], pws->b[6], pwt->b[6]); + pwd->b[7] = msa_binsl_df(DF_BYTE, pwd->b[7], pws->b[7], pwt->b[7]); + pwd->b[8] = msa_binsl_df(DF_BYTE, pwd->b[8], pws->b[8], pwt->b[8]); + pwd->b[9] = msa_binsl_df(DF_BYTE, pwd->b[9], pws->b[9], pwt->b[9]); + pwd->b[10] = msa_binsl_df(DF_BYTE, pwd->b[10], pws->b[10], pwt->b[10]); + pwd->b[11] = msa_binsl_df(DF_BYTE, pwd->b[11], pws->b[11], pwt->b[11]); + pwd->b[12] = msa_binsl_df(DF_BYTE, pwd->b[12], pws->b[12], pwt->b[12]); + pwd->b[13] = msa_binsl_df(DF_BYTE, pwd->b[13], pws->b[13], pwt->b[13]); + pwd->b[14] = msa_binsl_df(DF_BYTE, pwd->b[14], pws->b[14], pwt->b[14]); + pwd->b[15] = msa_binsl_df(DF_BYTE, pwd->b[15], pws->b[15], pwt->b[15]); +} + +void helper_msa_binsl_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_binsl_df(DF_HALF, pwd->h[0], pws->h[0], pwt->h[0]); + pwd->h[1] = msa_binsl_df(DF_HALF, pwd->h[1], pws->h[1], pwt->h[1]); + pwd->h[2] = msa_binsl_df(DF_HALF, pwd->h[2], pws->h[2], pwt->h[2]); + pwd->h[3] = msa_binsl_df(DF_HALF, pwd->h[3], pws->h[3], pwt->h[3]); + pwd->h[4] = msa_binsl_df(DF_HALF, pwd->h[4], pws->h[4], pwt->h[4]); + pwd->h[5] = msa_binsl_df(DF_HALF, pwd->h[5], pws->h[5], pwt->h[5]); + pwd->h[6] = msa_binsl_df(DF_HALF, pwd->h[6], pws->h[6], pwt->h[6]); + pwd->h[7] = msa_binsl_df(DF_HALF, pwd->h[7], pws->h[7], pwt->h[7]); +} + +void helper_msa_binsl_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_binsl_df(DF_WORD, pwd->w[0], pws->w[0], pwt->w[0]); + pwd->w[1] = msa_binsl_df(DF_WORD, pwd->w[1], pws->w[1], pwt->w[1]); + pwd->w[2] = msa_binsl_df(DF_WORD, pwd->w[2], pws->w[2], pwt->w[2]); + pwd->w[3] = msa_binsl_df(DF_WORD, pwd->w[3], pws->w[3], pwt->w[3]); +} + +void helper_msa_binsl_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_binsl_df(DF_DOUBLE, pwd->d[0], pws->d[0], pwt->d[0]); + pwd->d[1] = msa_binsl_df(DF_DOUBLE, pwd->d[1], pws->d[1], pwt->d[1]); +} + +static inline int64_t msa_binsr_df(uint32_t df, + int64_t dest, int64_t arg1, int64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t u_dest = UNSIGNED(dest, df); + int32_t sh_d = BIT_POSITION(arg2, df) + 1; + int32_t sh_a = DF_BITS(df) - sh_d; + if (sh_d == DF_BITS(df)) { + return u_arg1; + } else { + return UNSIGNED(UNSIGNED(u_dest >> sh_d, df) << sh_d, df) | + UNSIGNED(UNSIGNED(u_arg1 << sh_a, df) >> sh_a, df); + } +} + +void helper_msa_binsr_b(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_binsr_df(DF_BYTE, pwd->b[0], pws->b[0], pwt->b[0]); + pwd->b[1] = msa_binsr_df(DF_BYTE, pwd->b[1], pws->b[1], pwt->b[1]); + pwd->b[2] = msa_binsr_df(DF_BYTE, pwd->b[2], pws->b[2], pwt->b[2]); + pwd->b[3] = msa_binsr_df(DF_BYTE, pwd->b[3], pws->b[3], pwt->b[3]); + pwd->b[4] = msa_binsr_df(DF_BYTE, pwd->b[4], pws->b[4], pwt->b[4]); + pwd->b[5] = msa_binsr_df(DF_BYTE, pwd->b[5], pws->b[5], pwt->b[5]); + pwd->b[6] = msa_binsr_df(DF_BYTE, pwd->b[6], pws->b[6], pwt->b[6]); + pwd->b[7] = msa_binsr_df(DF_BYTE, pwd->b[7], pws->b[7], pwt->b[7]); + pwd->b[8] = msa_binsr_df(DF_BYTE, pwd->b[8], pws->b[8], pwt->b[8]); + pwd->b[9] = msa_binsr_df(DF_BYTE, pwd->b[9], pws->b[9], pwt->b[9]); + pwd->b[10] = msa_binsr_df(DF_BYTE, pwd->b[10], pws->b[10], pwt->b[10]); + pwd->b[11] = msa_binsr_df(DF_BYTE, pwd->b[11], pws->b[11], pwt->b[11]); + pwd->b[12] = msa_binsr_df(DF_BYTE, pwd->b[12], pws->b[12], pwt->b[12]); + pwd->b[13] = msa_binsr_df(DF_BYTE, pwd->b[13], pws->b[13], pwt->b[13]); + pwd->b[14] = msa_binsr_df(DF_BYTE, pwd->b[14], pws->b[14], pwt->b[14]); + pwd->b[15] = msa_binsr_df(DF_BYTE, pwd->b[15], pws->b[15], pwt->b[15]); +} + +void helper_msa_binsr_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_binsr_df(DF_HALF, pwd->h[0], pws->h[0], pwt->h[0]); + pwd->h[1] = msa_binsr_df(DF_HALF, pwd->h[1], pws->h[1], pwt->h[1]); + pwd->h[2] = msa_binsr_df(DF_HALF, pwd->h[2], pws->h[2], pwt->h[2]); + pwd->h[3] = msa_binsr_df(DF_HALF, pwd->h[3], pws->h[3], pwt->h[3]); + pwd->h[4] = msa_binsr_df(DF_HALF, pwd->h[4], pws->h[4], pwt->h[4]); + pwd->h[5] = msa_binsr_df(DF_HALF, pwd->h[5], pws->h[5], pwt->h[5]); + pwd->h[6] = msa_binsr_df(DF_HALF, pwd->h[6], pws->h[6], pwt->h[6]); + pwd->h[7] = msa_binsr_df(DF_HALF, pwd->h[7], pws->h[7], pwt->h[7]); +} + +void helper_msa_binsr_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_binsr_df(DF_WORD, pwd->w[0], pws->w[0], pwt->w[0]); + pwd->w[1] = msa_binsr_df(DF_WORD, pwd->w[1], pws->w[1], pwt->w[1]); + pwd->w[2] = msa_binsr_df(DF_WORD, pwd->w[2], pws->w[2], pwt->w[2]); + pwd->w[3] = msa_binsr_df(DF_WORD, pwd->w[3], pws->w[3], pwt->w[3]); +} + +void helper_msa_binsr_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_binsr_df(DF_DOUBLE, pwd->d[0], pws->d[0], pwt->d[0]); + pwd->d[1] = msa_binsr_df(DF_DOUBLE, pwd->d[1], pws->d[1], pwt->d[1]); +} + +void helper_msa_bmnz_v(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = UNSIGNED( \ + ((pwd->d[0] & (~pwt->d[0])) | (pws->d[0] & pwt->d[0])), DF_DOUBLE); + pwd->d[1] = UNSIGNED( \ + ((pwd->d[1] & (~pwt->d[1])) | (pws->d[1] & pwt->d[1])), DF_DOUBLE); +} + +void helper_msa_bmz_v(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = UNSIGNED( \ + ((pwd->d[0] & pwt->d[0]) | (pws->d[0] & (~pwt->d[0]))), DF_DOUBLE); + pwd->d[1] = UNSIGNED( \ + ((pwd->d[1] & pwt->d[1]) | (pws->d[1] & (~pwt->d[1]))), DF_DOUBLE); +} + +void helper_msa_bsel_v(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = UNSIGNED( \ + (pws->d[0] & (~pwd->d[0])) | (pwt->d[0] & pwd->d[0]), DF_DOUBLE); + pwd->d[1] = UNSIGNED( \ + (pws->d[1] & (~pwd->d[1])) | (pwt->d[1] & pwd->d[1]), DF_DOUBLE); +} /* @@ -110,7 +523,210 @@ * +---------------+----------------------------------------------------------+ */ -/* TODO: insert Bit Set group helpers here */ +static inline int64_t msa_bclr_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + int32_t b_arg2 = BIT_POSITION(arg2, df); + return UNSIGNED(arg1 & (~(1LL << b_arg2)), df); +} + +void helper_msa_bclr_b(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_bclr_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_bclr_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_bclr_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_bclr_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_bclr_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_bclr_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_bclr_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_bclr_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_bclr_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_bclr_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_bclr_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_bclr_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_bclr_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_bclr_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_bclr_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_bclr_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_bclr_h(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_bclr_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_bclr_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_bclr_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_bclr_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_bclr_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_bclr_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_bclr_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_bclr_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_bclr_w(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_bclr_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_bclr_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_bclr_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_bclr_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_bclr_d(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_bclr_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_bclr_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + +static inline int64_t msa_bneg_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + int32_t b_arg2 = BIT_POSITION(arg2, df); + return UNSIGNED(arg1 ^ (1LL << b_arg2), df); +} + +void helper_msa_bneg_b(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_bneg_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_bneg_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_bneg_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_bneg_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_bneg_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_bneg_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_bneg_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_bneg_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_bneg_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_bneg_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_bneg_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_bneg_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_bneg_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_bneg_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_bneg_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_bneg_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_bneg_h(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_bneg_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_bneg_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_bneg_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_bneg_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_bneg_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_bneg_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_bneg_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_bneg_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_bneg_w(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_bneg_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_bneg_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_bneg_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_bneg_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_bneg_d(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_bneg_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_bneg_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + +static inline int64_t msa_bset_df(uint32_t df, int64_t arg1, + int64_t arg2) +{ + int32_t b_arg2 = BIT_POSITION(arg2, df); + return UNSIGNED(arg1 | (1LL << b_arg2), df); +} + +void helper_msa_bset_b(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_bset_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_bset_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_bset_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_bset_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_bset_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_bset_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_bset_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_bset_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_bset_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_bset_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_bset_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_bset_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_bset_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_bset_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_bset_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_bset_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_bset_h(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_bset_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_bset_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_bset_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_bset_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_bset_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_bset_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_bset_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_bset_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_bset_w(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_bset_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_bset_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_bset_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_bset_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_bset_d(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_bset_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_bset_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} /* @@ -216,7 +832,297 @@ * +---------------+----------------------------------------------------------+ */ -/* TODO: insert Int Average group helpers here */ +static inline int64_t msa_ave_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + /* signed shift */ + return (arg1 >> 1) + (arg2 >> 1) + (arg1 & arg2 & 1); +} + +void helper_msa_ave_s_b(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_ave_s_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_ave_s_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_ave_s_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_ave_s_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_ave_s_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_ave_s_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_ave_s_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_ave_s_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_ave_s_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_ave_s_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_ave_s_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_ave_s_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_ave_s_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_ave_s_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_ave_s_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_ave_s_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_ave_s_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_ave_s_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_ave_s_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_ave_s_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_ave_s_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_ave_s_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_ave_s_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_ave_s_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_ave_s_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_ave_s_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_ave_s_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_ave_s_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_ave_s_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_ave_s_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_ave_s_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_ave_s_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_ave_s_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + +static inline uint64_t msa_ave_u_df(uint32_t df, uint64_t arg1, uint64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t u_arg2 = UNSIGNED(arg2, df); + /* unsigned shift */ + return (u_arg1 >> 1) + (u_arg2 >> 1) + (u_arg1 & u_arg2 & 1); +} + +void helper_msa_ave_u_b(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_ave_u_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_ave_u_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_ave_u_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_ave_u_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_ave_u_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_ave_u_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_ave_u_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_ave_u_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_ave_u_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_ave_u_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_ave_u_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_ave_u_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_ave_u_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_ave_u_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_ave_u_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_ave_u_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_ave_u_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_ave_u_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_ave_u_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_ave_u_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_ave_u_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_ave_u_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_ave_u_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_ave_u_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_ave_u_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_ave_u_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_ave_u_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_ave_u_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_ave_u_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_ave_u_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_ave_u_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_ave_u_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_ave_u_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + +static inline int64_t msa_aver_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + /* signed shift */ + return (arg1 >> 1) + (arg2 >> 1) + ((arg1 | arg2) & 1); +} + +void helper_msa_aver_s_b(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_aver_s_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_aver_s_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_aver_s_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_aver_s_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_aver_s_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_aver_s_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_aver_s_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_aver_s_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_aver_s_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_aver_s_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_aver_s_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_aver_s_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_aver_s_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_aver_s_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_aver_s_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_aver_s_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_aver_s_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_aver_s_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_aver_s_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_aver_s_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_aver_s_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_aver_s_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_aver_s_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_aver_s_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_aver_s_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_aver_s_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_aver_s_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_aver_s_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_aver_s_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_aver_s_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_aver_s_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_aver_s_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_aver_s_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + +static inline uint64_t msa_aver_u_df(uint32_t df, uint64_t arg1, uint64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t u_arg2 = UNSIGNED(arg2, df); + /* unsigned shift */ + return (u_arg1 >> 1) + (u_arg2 >> 1) + ((u_arg1 | u_arg2) & 1); +} + +void helper_msa_aver_u_b(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_aver_u_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_aver_u_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_aver_u_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_aver_u_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_aver_u_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_aver_u_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_aver_u_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_aver_u_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_aver_u_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_aver_u_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_aver_u_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_aver_u_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_aver_u_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_aver_u_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_aver_u_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_aver_u_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_aver_u_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_aver_u_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_aver_u_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_aver_u_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_aver_u_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_aver_u_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_aver_u_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_aver_u_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_aver_u_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_aver_u_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_aver_u_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_aver_u_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_aver_u_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_aver_u_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_aver_u_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_aver_u_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_aver_u_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} /* @@ -247,7 +1153,360 @@ * +---------------+----------------------------------------------------------+ */ -/* TODO: insert Int Compare group helpers here */ +static inline int64_t msa_ceq_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + return arg1 == arg2 ? -1 : 0; +} + +void helper_msa_ceq_b(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_ceq_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_ceq_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_ceq_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_ceq_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_ceq_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_ceq_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_ceq_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_ceq_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_ceq_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_ceq_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_ceq_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_ceq_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_ceq_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_ceq_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_ceq_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_ceq_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_ceq_h(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_ceq_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_ceq_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_ceq_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_ceq_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_ceq_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_ceq_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_ceq_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_ceq_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_ceq_w(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_ceq_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_ceq_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_ceq_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_ceq_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_ceq_d(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_ceq_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_ceq_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + +static inline int64_t msa_cle_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + return arg1 <= arg2 ? -1 : 0; +} + +void helper_msa_cle_s_b(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_cle_s_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_cle_s_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_cle_s_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_cle_s_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_cle_s_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_cle_s_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_cle_s_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_cle_s_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_cle_s_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_cle_s_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_cle_s_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_cle_s_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_cle_s_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_cle_s_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_cle_s_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_cle_s_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_cle_s_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_cle_s_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_cle_s_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_cle_s_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_cle_s_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_cle_s_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_cle_s_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_cle_s_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_cle_s_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_cle_s_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_cle_s_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_cle_s_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_cle_s_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_cle_s_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_cle_s_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_cle_s_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_cle_s_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + +static inline int64_t msa_cle_u_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t u_arg2 = UNSIGNED(arg2, df); + return u_arg1 <= u_arg2 ? -1 : 0; +} + +void helper_msa_cle_u_b(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_cle_u_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_cle_u_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_cle_u_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_cle_u_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_cle_u_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_cle_u_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_cle_u_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_cle_u_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_cle_u_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_cle_u_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_cle_u_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_cle_u_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_cle_u_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_cle_u_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_cle_u_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_cle_u_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_cle_u_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_cle_u_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_cle_u_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_cle_u_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_cle_u_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_cle_u_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_cle_u_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_cle_u_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_cle_u_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_cle_u_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_cle_u_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_cle_u_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_cle_u_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_cle_u_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_cle_u_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_cle_u_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_cle_u_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + +static inline int64_t msa_clt_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + return arg1 < arg2 ? -1 : 0; +} + +void helper_msa_clt_s_b(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_clt_s_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_clt_s_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_clt_s_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_clt_s_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_clt_s_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_clt_s_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_clt_s_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_clt_s_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_clt_s_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_clt_s_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_clt_s_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_clt_s_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_clt_s_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_clt_s_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_clt_s_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_clt_s_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_clt_s_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_clt_s_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_clt_s_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_clt_s_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_clt_s_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_clt_s_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_clt_s_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_clt_s_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_clt_s_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_clt_s_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_clt_s_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_clt_s_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_clt_s_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_clt_s_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_clt_s_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_clt_s_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_clt_s_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + +static inline int64_t msa_clt_u_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t u_arg2 = UNSIGNED(arg2, df); + return u_arg1 < u_arg2 ? -1 : 0; +} + +void helper_msa_clt_u_b(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_clt_u_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_clt_u_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_clt_u_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_clt_u_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_clt_u_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_clt_u_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_clt_u_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_clt_u_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_clt_u_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_clt_u_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_clt_u_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_clt_u_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_clt_u_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_clt_u_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_clt_u_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_clt_u_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_clt_u_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_clt_u_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_clt_u_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_clt_u_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_clt_u_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_clt_u_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_clt_u_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_clt_u_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_clt_u_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_clt_u_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_clt_u_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_clt_u_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_clt_u_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_clt_u_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_clt_u_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_clt_u_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_clt_u_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} /* @@ -266,7 +1525,154 @@ * +---------------+----------------------------------------------------------+ */ -/* TODO: insert Int Divide group helpers here */ + +static inline int64_t msa_div_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + if (arg1 == DF_MIN_INT(df) && arg2 == -1) { + return DF_MIN_INT(df); + } + return arg2 ? arg1 / arg2 + : arg1 >= 0 ? -1 : 1; +} + +void helper_msa_div_s_b(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_div_s_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_div_s_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_div_s_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_div_s_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_div_s_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_div_s_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_div_s_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_div_s_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_div_s_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_div_s_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_div_s_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_div_s_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_div_s_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_div_s_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_div_s_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_div_s_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_div_s_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_div_s_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_div_s_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_div_s_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_div_s_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_div_s_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_div_s_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_div_s_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_div_s_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_div_s_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_div_s_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_div_s_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_div_s_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_div_s_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_div_s_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_div_s_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_div_s_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + +static inline int64_t msa_div_u_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t u_arg2 = UNSIGNED(arg2, df); + return arg2 ? u_arg1 / u_arg2 : -1; +} + +void helper_msa_div_u_b(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_div_u_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_div_u_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_div_u_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_div_u_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_div_u_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_div_u_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_div_u_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_div_u_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_div_u_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_div_u_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_div_u_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_div_u_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_div_u_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_div_u_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_div_u_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_div_u_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_div_u_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_div_u_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_div_u_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_div_u_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_div_u_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_div_u_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_div_u_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_div_u_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_div_u_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_div_u_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_div_u_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_div_u_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_div_u_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_div_u_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_div_u_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_div_u_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_div_u_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} /* @@ -349,7 +1755,152 @@ * +---------------+----------------------------------------------------------+ */ -/* TODO: insert Int Modulo group helpers here */ +static inline int64_t msa_mod_s_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + if (arg1 == DF_MIN_INT(df) && arg2 == -1) { + return 0; + } + return arg2 ? arg1 % arg2 : arg1; +} + +void helper_msa_mod_s_b(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_mod_s_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_mod_s_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_mod_s_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_mod_s_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_mod_s_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_mod_s_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_mod_s_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_mod_s_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_mod_s_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_mod_s_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_mod_s_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_mod_s_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_mod_s_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_mod_s_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_mod_s_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_mod_s_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_mod_s_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_mod_s_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_mod_s_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_mod_s_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_mod_s_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_mod_s_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_mod_s_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_mod_s_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_mod_s_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_mod_s_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_mod_s_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_mod_s_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_mod_s_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_mod_s_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_mod_s_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_mod_s_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_mod_s_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} + +static inline int64_t msa_mod_u_df(uint32_t df, int64_t arg1, int64_t arg2) +{ + uint64_t u_arg1 = UNSIGNED(arg1, df); + uint64_t u_arg2 = UNSIGNED(arg2, df); + return u_arg2 ? u_arg1 % u_arg2 : u_arg1; +} + +void helper_msa_mod_u_b(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->b[0] = msa_mod_u_df(DF_BYTE, pws->b[0], pwt->b[0]); + pwd->b[1] = msa_mod_u_df(DF_BYTE, pws->b[1], pwt->b[1]); + pwd->b[2] = msa_mod_u_df(DF_BYTE, pws->b[2], pwt->b[2]); + pwd->b[3] = msa_mod_u_df(DF_BYTE, pws->b[3], pwt->b[3]); + pwd->b[4] = msa_mod_u_df(DF_BYTE, pws->b[4], pwt->b[4]); + pwd->b[5] = msa_mod_u_df(DF_BYTE, pws->b[5], pwt->b[5]); + pwd->b[6] = msa_mod_u_df(DF_BYTE, pws->b[6], pwt->b[6]); + pwd->b[7] = msa_mod_u_df(DF_BYTE, pws->b[7], pwt->b[7]); + pwd->b[8] = msa_mod_u_df(DF_BYTE, pws->b[8], pwt->b[8]); + pwd->b[9] = msa_mod_u_df(DF_BYTE, pws->b[9], pwt->b[9]); + pwd->b[10] = msa_mod_u_df(DF_BYTE, pws->b[10], pwt->b[10]); + pwd->b[11] = msa_mod_u_df(DF_BYTE, pws->b[11], pwt->b[11]); + pwd->b[12] = msa_mod_u_df(DF_BYTE, pws->b[12], pwt->b[12]); + pwd->b[13] = msa_mod_u_df(DF_BYTE, pws->b[13], pwt->b[13]); + pwd->b[14] = msa_mod_u_df(DF_BYTE, pws->b[14], pwt->b[14]); + pwd->b[15] = msa_mod_u_df(DF_BYTE, pws->b[15], pwt->b[15]); +} + +void helper_msa_mod_u_h(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->h[0] = msa_mod_u_df(DF_HALF, pws->h[0], pwt->h[0]); + pwd->h[1] = msa_mod_u_df(DF_HALF, pws->h[1], pwt->h[1]); + pwd->h[2] = msa_mod_u_df(DF_HALF, pws->h[2], pwt->h[2]); + pwd->h[3] = msa_mod_u_df(DF_HALF, pws->h[3], pwt->h[3]); + pwd->h[4] = msa_mod_u_df(DF_HALF, pws->h[4], pwt->h[4]); + pwd->h[5] = msa_mod_u_df(DF_HALF, pws->h[5], pwt->h[5]); + pwd->h[6] = msa_mod_u_df(DF_HALF, pws->h[6], pwt->h[6]); + pwd->h[7] = msa_mod_u_df(DF_HALF, pws->h[7], pwt->h[7]); +} + +void helper_msa_mod_u_w(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->w[0] = msa_mod_u_df(DF_WORD, pws->w[0], pwt->w[0]); + pwd->w[1] = msa_mod_u_df(DF_WORD, pws->w[1], pwt->w[1]); + pwd->w[2] = msa_mod_u_df(DF_WORD, pws->w[2], pwt->w[2]); + pwd->w[3] = msa_mod_u_df(DF_WORD, pws->w[3], pwt->w[3]); +} + +void helper_msa_mod_u_d(CPUMIPSState *env, + uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = msa_mod_u_df(DF_DOUBLE, pws->d[0], pwt->d[0]); + pwd->d[1] = msa_mod_u_df(DF_DOUBLE, pws->d[1], pwt->d[1]); +} /* @@ -459,7 +2010,46 @@ * +---------------+----------------------------------------------------------+ */ -/* TODO: insert Logic group helpers here */ + +void helper_msa_and_v(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = pws->d[0] & pwt->d[0]; + pwd->d[1] = pws->d[1] & pwt->d[1]; +} + +void helper_msa_nor_v(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = ~(pws->d[0] | pwt->d[0]); + pwd->d[1] = ~(pws->d[1] | pwt->d[1]); +} + +void helper_msa_or_v(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = pws->d[0] | pwt->d[0]; + pwd->d[1] = pws->d[1] | pwt->d[1]; +} + +void helper_msa_xor_v(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); + + pwd->d[0] = pws->d[0] ^ pwt->d[0]; + pwd->d[1] = pws->d[1] ^ pwt->d[1]; +} /* @@ -471,7 +2061,19 @@ * +---------------+----------------------------------------------------------+ */ -/* TODO: insert Move group helpers here */ +static inline void msa_move_v(wr_t *pwd, wr_t *pws) +{ + pwd->d[0] = pws->d[0]; + pwd->d[1] = pws->d[1]; +} + +void helper_msa_move_v(CPUMIPSState *env, uint32_t wd, uint32_t ws) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + wr_t *pws = &(env->active_fpu.fpr[ws].wr); + + msa_move_v(pwd, pws); +} /* @@ -528,15 +2130,6 @@ /* TODO: insert Shift group helpers here */ -static inline void msa_move_v(wr_t *pwd, wr_t *pws) -{ - uint32_t i; - - for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { - pwd->d[i] = pws->d[i]; - } -} - #define MSA_FN_IMM8(FUNC, DEST, OPERATION) \ void helper_msa_ ## FUNC(CPUMIPSState *env, uint32_t wd, uint32_t ws, \ uint32_t i8) \ @@ -569,6 +2162,9 @@ MSA_FN_IMM8(bmzi_b, pwd->b[i], MSA_FN_IMM8(bseli_b, pwd->b[i], BIT_SELECT(pwd->b[i], pws->b[i], i8, DF_BYTE)) +#undef BIT_SELECT +#undef BIT_MOVE_IF_ZERO +#undef BIT_MOVE_IF_NOT_ZERO #undef MSA_FN_IMM8 #define SHF_POS(i, imm) (((i) & 0xfc) + (((imm) >> (2 * ((i) & 0x03))) & 0x03)) @@ -603,70 +2199,6 @@ void helper_msa_shf_df(CPUMIPSState *env, uint32_t df, uint32_t wd, msa_move_v(pwd, pwx); } -#define MSA_FN_VECTOR(FUNC, DEST, OPERATION) \ -void helper_msa_ ## FUNC(CPUMIPSState *env, uint32_t wd, uint32_t ws, \ - uint32_t wt) \ -{ \ - wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ - wr_t *pws = &(env->active_fpu.fpr[ws].wr); \ - wr_t *pwt = &(env->active_fpu.fpr[wt].wr); \ - uint32_t i; \ - for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { \ - DEST = OPERATION; \ - } \ -} - -MSA_FN_VECTOR(bmnz_v, pwd->d[i], - BIT_MOVE_IF_NOT_ZERO(pwd->d[i], pws->d[i], pwt->d[i], DF_DOUBLE)) -MSA_FN_VECTOR(bmz_v, pwd->d[i], - BIT_MOVE_IF_ZERO(pwd->d[i], pws->d[i], pwt->d[i], DF_DOUBLE)) -MSA_FN_VECTOR(bsel_v, pwd->d[i], - BIT_SELECT(pwd->d[i], pws->d[i], pwt->d[i], DF_DOUBLE)) -#undef BIT_MOVE_IF_NOT_ZERO -#undef BIT_MOVE_IF_ZERO -#undef BIT_SELECT -#undef MSA_FN_VECTOR - -void helper_msa_and_v(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) -{ - wr_t *pwd = &(env->active_fpu.fpr[wd].wr); - wr_t *pws = &(env->active_fpu.fpr[ws].wr); - wr_t *pwt = &(env->active_fpu.fpr[wt].wr); - - pwd->d[0] = pws->d[0] & pwt->d[0]; - pwd->d[1] = pws->d[1] & pwt->d[1]; -} - -void helper_msa_or_v(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) -{ - wr_t *pwd = &(env->active_fpu.fpr[wd].wr); - wr_t *pws = &(env->active_fpu.fpr[ws].wr); - wr_t *pwt = &(env->active_fpu.fpr[wt].wr); - - pwd->d[0] = pws->d[0] | pwt->d[0]; - pwd->d[1] = pws->d[1] | pwt->d[1]; -} - -void helper_msa_nor_v(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) -{ - wr_t *pwd = &(env->active_fpu.fpr[wd].wr); - wr_t *pws = &(env->active_fpu.fpr[ws].wr); - wr_t *pwt = &(env->active_fpu.fpr[wt].wr); - - pwd->d[0] = ~(pws->d[0] | pwt->d[0]); - pwd->d[1] = ~(pws->d[1] | pwt->d[1]); -} - -void helper_msa_xor_v(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt) -{ - wr_t *pwd = &(env->active_fpu.fpr[wd].wr); - wr_t *pws = &(env->active_fpu.fpr[ws].wr); - wr_t *pwt = &(env->active_fpu.fpr[wt].wr); - - pwd->d[0] = pws->d[0] ^ pwt->d[0]; - pwd->d[1] = pws->d[1] ^ pwt->d[1]; -} - static inline int64_t msa_addv_df(uint32_t df, int64_t arg1, int64_t arg2) { return arg1 + arg2; @@ -677,35 +2209,6 @@ static inline int64_t msa_subv_df(uint32_t df, int64_t arg1, int64_t arg2) return arg1 - arg2; } -static inline int64_t msa_ceq_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - return arg1 == arg2 ? -1 : 0; -} - -static inline int64_t msa_cle_s_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - return arg1 <= arg2 ? -1 : 0; -} - -static inline int64_t msa_cle_u_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - uint64_t u_arg1 = UNSIGNED(arg1, df); - uint64_t u_arg2 = UNSIGNED(arg2, df); - return u_arg1 <= u_arg2 ? -1 : 0; -} - -static inline int64_t msa_clt_s_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - return arg1 < arg2 ? -1 : 0; -} - -static inline int64_t msa_clt_u_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - uint64_t u_arg1 = UNSIGNED(arg1, df); - uint64_t u_arg2 = UNSIGNED(arg2, df); - return u_arg1 < u_arg2 ? -1 : 0; -} - static inline int64_t msa_max_s_df(uint32_t df, int64_t arg1, int64_t arg2) { return arg1 > arg2 ? arg1 : arg2; @@ -809,9 +2312,6 @@ void helper_msa_ldi_df(CPUMIPSState *env, uint32_t df, uint32_t wd, } } -/* Data format bit position and unsigned values */ -#define BIT_POSITION(x, df) ((uint64_t)(x) % DF_BITS(df)) - static inline int64_t msa_sll_df(uint32_t df, int64_t arg1, int64_t arg2) { int32_t b_arg2 = BIT_POSITION(arg2, df); @@ -831,55 +2331,6 @@ static inline int64_t msa_srl_df(uint32_t df, int64_t arg1, int64_t arg2) return u_arg1 >> b_arg2; } -static inline int64_t msa_bclr_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - int32_t b_arg2 = BIT_POSITION(arg2, df); - return UNSIGNED(arg1 & (~(1LL << b_arg2)), df); -} - -static inline int64_t msa_bset_df(uint32_t df, int64_t arg1, - int64_t arg2) -{ - int32_t b_arg2 = BIT_POSITION(arg2, df); - return UNSIGNED(arg1 | (1LL << b_arg2), df); -} - -static inline int64_t msa_bneg_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - int32_t b_arg2 = BIT_POSITION(arg2, df); - return UNSIGNED(arg1 ^ (1LL << b_arg2), df); -} - -static inline int64_t msa_binsl_df(uint32_t df, int64_t dest, int64_t arg1, - int64_t arg2) -{ - uint64_t u_arg1 = UNSIGNED(arg1, df); - uint64_t u_dest = UNSIGNED(dest, df); - int32_t sh_d = BIT_POSITION(arg2, df) + 1; - int32_t sh_a = DF_BITS(df) - sh_d; - if (sh_d == DF_BITS(df)) { - return u_arg1; - } else { - return UNSIGNED(UNSIGNED(u_dest << sh_d, df) >> sh_d, df) | - UNSIGNED(UNSIGNED(u_arg1 >> sh_a, df) << sh_a, df); - } -} - -static inline int64_t msa_binsr_df(uint32_t df, int64_t dest, int64_t arg1, - int64_t arg2) -{ - uint64_t u_arg1 = UNSIGNED(arg1, df); - uint64_t u_dest = UNSIGNED(dest, df); - int32_t sh_d = BIT_POSITION(arg2, df) + 1; - int32_t sh_a = DF_BITS(df) - sh_d; - if (sh_d == DF_BITS(df)) { - return u_arg1; - } else { - return UNSIGNED(UNSIGNED(u_dest >> sh_d, df) << sh_d, df) | - UNSIGNED(UNSIGNED(u_arg1 << sh_a, df) >> sh_a, df); - } -} - static inline int64_t msa_sat_s_df(uint32_t df, int64_t arg, uint32_t m) { return arg < M_MIN_INT(m + 1) ? M_MIN_INT(m + 1) : @@ -1057,34 +2508,6 @@ static inline uint64_t msa_adds_u_df(uint32_t df, uint64_t arg1, uint64_t arg2) return (u_arg1 < max_uint - u_arg2) ? u_arg1 + u_arg2 : max_uint; } -static inline int64_t msa_ave_s_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - /* signed shift */ - return (arg1 >> 1) + (arg2 >> 1) + (arg1 & arg2 & 1); -} - -static inline uint64_t msa_ave_u_df(uint32_t df, uint64_t arg1, uint64_t arg2) -{ - uint64_t u_arg1 = UNSIGNED(arg1, df); - uint64_t u_arg2 = UNSIGNED(arg2, df); - /* unsigned shift */ - return (u_arg1 >> 1) + (u_arg2 >> 1) + (u_arg1 & u_arg2 & 1); -} - -static inline int64_t msa_aver_s_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - /* signed shift */ - return (arg1 >> 1) + (arg2 >> 1) + ((arg1 | arg2) & 1); -} - -static inline uint64_t msa_aver_u_df(uint32_t df, uint64_t arg1, uint64_t arg2) -{ - uint64_t u_arg1 = UNSIGNED(arg1, df); - uint64_t u_arg2 = UNSIGNED(arg2, df); - /* unsigned shift */ - return (u_arg1 >> 1) + (u_arg2 >> 1) + ((u_arg1 | u_arg2) & 1); -} - static inline int64_t msa_subs_s_df(uint32_t df, int64_t arg1, int64_t arg2) { int64_t max_int = DF_MAX_INT(df); @@ -1158,37 +2581,6 @@ static inline int64_t msa_mulv_df(uint32_t df, int64_t arg1, int64_t arg2) return arg1 * arg2; } -static inline int64_t msa_div_s_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - if (arg1 == DF_MIN_INT(df) && arg2 == -1) { - return DF_MIN_INT(df); - } - return arg2 ? arg1 / arg2 - : arg1 >= 0 ? -1 : 1; -} - -static inline int64_t msa_div_u_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - uint64_t u_arg1 = UNSIGNED(arg1, df); - uint64_t u_arg2 = UNSIGNED(arg2, df); - return arg2 ? u_arg1 / u_arg2 : -1; -} - -static inline int64_t msa_mod_s_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - if (arg1 == DF_MIN_INT(df) && arg2 == -1) { - return 0; - } - return arg2 ? arg1 % arg2 : arg1; -} - -static inline int64_t msa_mod_u_df(uint32_t df, int64_t arg1, int64_t arg2) -{ - uint64_t u_arg1 = UNSIGNED(arg1, df); - uint64_t u_arg2 = UNSIGNED(arg2, df); - return u_arg2 ? u_arg1 % u_arg2 : u_arg1; -} - #define SIGNED_EVEN(a, df) \ ((((int64_t)(a)) << (64 - DF_BITS(df) / 2)) >> (64 - DF_BITS(df) / 2)) @@ -1375,9 +2767,6 @@ void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, \ MSA_BINOP_DF(sll) MSA_BINOP_DF(sra) MSA_BINOP_DF(srl) -MSA_BINOP_DF(bclr) -MSA_BINOP_DF(bset) -MSA_BINOP_DF(bneg) MSA_BINOP_DF(addv) MSA_BINOP_DF(subv) MSA_BINOP_DF(max_s) @@ -1386,19 +2775,10 @@ MSA_BINOP_DF(min_s) MSA_BINOP_DF(min_u) MSA_BINOP_DF(max_a) MSA_BINOP_DF(min_a) -MSA_BINOP_DF(ceq) -MSA_BINOP_DF(clt_s) -MSA_BINOP_DF(clt_u) -MSA_BINOP_DF(cle_s) -MSA_BINOP_DF(cle_u) MSA_BINOP_DF(add_a) MSA_BINOP_DF(adds_a) MSA_BINOP_DF(adds_s) MSA_BINOP_DF(adds_u) -MSA_BINOP_DF(ave_s) -MSA_BINOP_DF(ave_u) -MSA_BINOP_DF(aver_s) -MSA_BINOP_DF(aver_u) MSA_BINOP_DF(subs_s) MSA_BINOP_DF(subs_u) MSA_BINOP_DF(subsus_u) @@ -1406,10 +2786,6 @@ MSA_BINOP_DF(subsuu_s) MSA_BINOP_DF(asub_s) MSA_BINOP_DF(asub_u) MSA_BINOP_DF(mulv) -MSA_BINOP_DF(div_s) -MSA_BINOP_DF(div_u) -MSA_BINOP_DF(mod_s) -MSA_BINOP_DF(mod_u) MSA_BINOP_DF(dotp_s) MSA_BINOP_DF(dotp_u) MSA_BINOP_DF(srar) @@ -2500,56 +3876,6 @@ target_ulong helper_msa_cfcmsa(CPUMIPSState *env, uint32_t cs) return 0; } -void helper_msa_move_v(CPUMIPSState *env, uint32_t wd, uint32_t ws) -{ - wr_t *pwd = &(env->active_fpu.fpr[wd].wr); - wr_t *pws = &(env->active_fpu.fpr[ws].wr); - - msa_move_v(pwd, pws); -} - -static inline int64_t msa_pcnt_df(uint32_t df, int64_t arg) -{ - uint64_t x; - - x = UNSIGNED(arg, df); - - x = (x & 0x5555555555555555ULL) + ((x >> 1) & 0x5555555555555555ULL); - x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL); - x = (x & 0x0F0F0F0F0F0F0F0FULL) + ((x >> 4) & 0x0F0F0F0F0F0F0F0FULL); - x = (x & 0x00FF00FF00FF00FFULL) + ((x >> 8) & 0x00FF00FF00FF00FFULL); - x = (x & 0x0000FFFF0000FFFFULL) + ((x >> 16) & 0x0000FFFF0000FFFFULL); - x = (x & 0x00000000FFFFFFFFULL) + ((x >> 32)); - - return x; -} - -static inline int64_t msa_nlzc_df(uint32_t df, int64_t arg) -{ - uint64_t x, y; - int n, c; - - x = UNSIGNED(arg, df); - n = DF_BITS(df); - c = DF_BITS(df) / 2; - - do { - y = x >> c; - if (y != 0) { - n = n - c; - x = y; - } - c = c >> 1; - } while (c != 0); - - return n - x; -} - -static inline int64_t msa_nloc_df(uint32_t df, int64_t arg) -{ - return msa_nlzc_df(df, UNSIGNED((~arg), df)); -} - void helper_msa_fill_df(CPUMIPSState *env, uint32_t df, uint32_t wd, uint32_t rs) { @@ -2582,61 +3908,6 @@ void helper_msa_fill_df(CPUMIPSState *env, uint32_t df, uint32_t wd, } } -#define MSA_UNOP_DF(func) \ -void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, \ - uint32_t wd, uint32_t ws) \ -{ \ - wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ - wr_t *pws = &(env->active_fpu.fpr[ws].wr); \ - \ - switch (df) { \ - case DF_BYTE: \ - pwd->b[0] = msa_ ## func ## _df(df, pws->b[0]); \ - pwd->b[1] = msa_ ## func ## _df(df, pws->b[1]); \ - pwd->b[2] = msa_ ## func ## _df(df, pws->b[2]); \ - pwd->b[3] = msa_ ## func ## _df(df, pws->b[3]); \ - pwd->b[4] = msa_ ## func ## _df(df, pws->b[4]); \ - pwd->b[5] = msa_ ## func ## _df(df, pws->b[5]); \ - pwd->b[6] = msa_ ## func ## _df(df, pws->b[6]); \ - pwd->b[7] = msa_ ## func ## _df(df, pws->b[7]); \ - pwd->b[8] = msa_ ## func ## _df(df, pws->b[8]); \ - pwd->b[9] = msa_ ## func ## _df(df, pws->b[9]); \ - pwd->b[10] = msa_ ## func ## _df(df, pws->b[10]); \ - pwd->b[11] = msa_ ## func ## _df(df, pws->b[11]); \ - pwd->b[12] = msa_ ## func ## _df(df, pws->b[12]); \ - pwd->b[13] = msa_ ## func ## _df(df, pws->b[13]); \ - pwd->b[14] = msa_ ## func ## _df(df, pws->b[14]); \ - pwd->b[15] = msa_ ## func ## _df(df, pws->b[15]); \ - break; \ - case DF_HALF: \ - pwd->h[0] = msa_ ## func ## _df(df, pws->h[0]); \ - pwd->h[1] = msa_ ## func ## _df(df, pws->h[1]); \ - pwd->h[2] = msa_ ## func ## _df(df, pws->h[2]); \ - pwd->h[3] = msa_ ## func ## _df(df, pws->h[3]); \ - pwd->h[4] = msa_ ## func ## _df(df, pws->h[4]); \ - pwd->h[5] = msa_ ## func ## _df(df, pws->h[5]); \ - pwd->h[6] = msa_ ## func ## _df(df, pws->h[6]); \ - pwd->h[7] = msa_ ## func ## _df(df, pws->h[7]); \ - break; \ - case DF_WORD: \ - pwd->w[0] = msa_ ## func ## _df(df, pws->w[0]); \ - pwd->w[1] = msa_ ## func ## _df(df, pws->w[1]); \ - pwd->w[2] = msa_ ## func ## _df(df, pws->w[2]); \ - pwd->w[3] = msa_ ## func ## _df(df, pws->w[3]); \ - break; \ - case DF_DOUBLE: \ - pwd->d[0] = msa_ ## func ## _df(df, pws->d[0]); \ - pwd->d[1] = msa_ ## func ## _df(df, pws->d[1]); \ - break; \ - default: \ - assert(0); \ - } \ -} - -MSA_UNOP_DF(nlzc) -MSA_UNOP_DF(nloc) -MSA_UNOP_DF(pcnt) -#undef MSA_UNOP_DF #define FLOAT_ONE32 make_float32(0x3f8 << 20) #define FLOAT_ONE64 make_float64(0x3ffULL << 52) diff --git a/target/mips/translate.c b/target/mips/translate.c index f2119955cf..50397167fc 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -7118,7 +7118,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) tcg_gen_andi_tl(arg, arg, ~0xffff); register_name = "BadInstrX"; break; - default: + default: goto cp0_unimplemented; } break; @@ -7545,7 +7545,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REG31__KSCRATCH6: CP0_CHECK(ctx->kscrexist & (1 << sel)); tcg_gen_ld_tl(arg, cpu_env, - offsetof(CPUMIPSState, CP0_KScratch[sel-2])); + offsetof(CPUMIPSState, CP0_KScratch[sel - 2])); tcg_gen_ext32s_tl(arg, arg); register_name = "KScratch"; break; @@ -8295,7 +8295,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REG31__KSCRATCH6: CP0_CHECK(ctx->kscrexist & (1 << sel)); tcg_gen_st_tl(arg, cpu_env, - offsetof(CPUMIPSState, CP0_KScratch[sel-2])); + offsetof(CPUMIPSState, CP0_KScratch[sel - 2])); register_name = "KScratch"; break; default: @@ -8387,17 +8387,20 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REG01__YQMASK: CP0_CHECK(ctx->insn_flags & ASE_MT); - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_YQMask)); + tcg_gen_ld_tl(arg, cpu_env, + offsetof(CPUMIPSState, CP0_YQMask)); register_name = "YQMask"; break; case CP0_REG01__VPESCHEDULE: CP0_CHECK(ctx->insn_flags & ASE_MT); - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPESchedule)); + tcg_gen_ld_tl(arg, cpu_env, + offsetof(CPUMIPSState, CP0_VPESchedule)); register_name = "VPESchedule"; break; case CP0_REG01__VPESCHEFBACK: CP0_CHECK(ctx->insn_flags & ASE_MT); - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPEScheFBack)); + tcg_gen_ld_tl(arg, cpu_env, + offsetof(CPUMIPSState, CP0_VPEScheFBack)); register_name = "VPEScheFBack"; break; case CP0_REG01__VPEOPT: @@ -8412,7 +8415,8 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REGISTER_02: switch (sel) { case CP0_REG02__ENTRYLO0: - tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryLo0)); + tcg_gen_ld_tl(arg, cpu_env, + offsetof(CPUMIPSState, CP0_EntryLo0)); register_name = "EntryLo0"; break; case CP0_REG02__TCSTATUS: @@ -8756,7 +8760,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config5)); register_name = "Config5"; break; - /* 6,7 are implementation dependent */ + /* 6,7 are implementation dependent */ case CP0_REG16__CONFIG6: gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config6)); register_name = "Config6"; @@ -8837,7 +8841,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) } break; case CP0_REGISTER_21: - /* Officially reserved, but sel 0 is used for R1x000 framemask */ + /* Officially reserved, but sel 0 is used for R1x000 framemask */ CP0_CHECK(!(ctx->insn_flags & ISA_MIPS32R6)); switch (sel) { case 0: @@ -9022,7 +9026,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case CP0_REG31__KSCRATCH6: CP0_CHECK(ctx->kscrexist & (1 << sel)); tcg_gen_ld_tl(arg, cpu_env, - offsetof(CPUMIPSState, CP0_KScratch[sel-2])); + offsetof(CPUMIPSState, CP0_KScratch[sel - 2])); register_name = "KScratch"; break; default: @@ -9112,12 +9116,14 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) break; case CP0_REG01__VPESCHEDULE: CP0_CHECK(ctx->insn_flags & ASE_MT); - tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPESchedule)); + tcg_gen_st_tl(arg, cpu_env, + offsetof(CPUMIPSState, CP0_VPESchedule)); register_name = "VPESchedule"; break; case CP0_REG01__VPESCHEFBACK: CP0_CHECK(ctx->insn_flags & ASE_MT); - tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPEScheFBack)); + tcg_gen_st_tl(arg, cpu_env, + offsetof(CPUMIPSState, CP0_VPEScheFBack)); register_name = "VPEScheFBack"; break; case CP0_REG01__VPEOPT: @@ -28380,15 +28386,300 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) TCGv_i32 twt = tcg_const_i32(wt); switch (MASK_MSA_3R(ctx->opcode)) { + case OPC_BINSL_df: + switch (df) { + case DF_BYTE: + gen_helper_msa_binsl_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_binsl_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_binsl_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_binsl_d(cpu_env, twd, tws, twt); + break; + } + break; + case OPC_BINSR_df: + switch (df) { + case DF_BYTE: + gen_helper_msa_binsr_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_binsr_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_binsr_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_binsr_d(cpu_env, twd, tws, twt); + break; + } + break; + case OPC_BCLR_df: + switch (df) { + case DF_BYTE: + gen_helper_msa_bclr_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_bclr_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_bclr_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_bclr_d(cpu_env, twd, tws, twt); + break; + } + break; + case OPC_BNEG_df: + switch (df) { + case DF_BYTE: + gen_helper_msa_bneg_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_bneg_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_bneg_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_bneg_d(cpu_env, twd, tws, twt); + break; + } + break; + case OPC_BSET_df: + switch (df) { + case DF_BYTE: + gen_helper_msa_bset_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_bset_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_bset_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_bset_d(cpu_env, twd, tws, twt); + break; + } + break; + case OPC_AVE_S_df: + switch (df) { + case DF_BYTE: + gen_helper_msa_ave_s_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_ave_s_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_ave_s_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_ave_s_d(cpu_env, twd, tws, twt); + break; + } + break; + case OPC_AVE_U_df: + switch (df) { + case DF_BYTE: + gen_helper_msa_ave_u_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_ave_u_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_ave_u_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_ave_u_d(cpu_env, twd, tws, twt); + break; + } + break; + case OPC_AVER_S_df: + switch (df) { + case DF_BYTE: + gen_helper_msa_aver_s_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_aver_s_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_aver_s_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_aver_s_d(cpu_env, twd, tws, twt); + break; + } + break; + case OPC_AVER_U_df: + switch (df) { + case DF_BYTE: + gen_helper_msa_aver_u_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_aver_u_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_aver_u_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_aver_u_d(cpu_env, twd, tws, twt); + break; + } + break; + case OPC_CEQ_df: + switch (df) { + case DF_BYTE: + gen_helper_msa_ceq_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_ceq_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_ceq_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_ceq_d(cpu_env, twd, tws, twt); + break; + } + break; + case OPC_CLE_S_df: + switch (df) { + case DF_BYTE: + gen_helper_msa_cle_s_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_cle_s_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_cle_s_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_cle_s_d(cpu_env, twd, tws, twt); + break; + } + break; + case OPC_CLE_U_df: + switch (df) { + case DF_BYTE: + gen_helper_msa_cle_u_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_cle_u_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_cle_u_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_cle_u_d(cpu_env, twd, tws, twt); + break; + } + break; + case OPC_CLT_S_df: + switch (df) { + case DF_BYTE: + gen_helper_msa_clt_s_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_clt_s_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_clt_s_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_clt_s_d(cpu_env, twd, tws, twt); + break; + } + break; + case OPC_CLT_U_df: + switch (df) { + case DF_BYTE: + gen_helper_msa_clt_u_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_clt_u_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_clt_u_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_clt_u_d(cpu_env, twd, tws, twt); + break; + } + break; + case OPC_DIV_S_df: + switch (df) { + case DF_BYTE: + gen_helper_msa_div_s_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_div_s_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_div_s_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_div_s_d(cpu_env, twd, tws, twt); + break; + } + break; + case OPC_DIV_U_df: + switch (df) { + case DF_BYTE: + gen_helper_msa_div_u_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_div_u_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_div_u_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_div_u_d(cpu_env, twd, tws, twt); + break; + } + break; + case OPC_MOD_S_df: + switch (df) { + case DF_BYTE: + gen_helper_msa_mod_s_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_mod_s_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_mod_s_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_mod_s_d(cpu_env, twd, tws, twt); + break; + } + break; + case OPC_MOD_U_df: + switch (df) { + case DF_BYTE: + gen_helper_msa_mod_u_b(cpu_env, twd, tws, twt); + break; + case DF_HALF: + gen_helper_msa_mod_u_h(cpu_env, twd, tws, twt); + break; + case DF_WORD: + gen_helper_msa_mod_u_w(cpu_env, twd, tws, twt); + break; + case DF_DOUBLE: + gen_helper_msa_mod_u_d(cpu_env, twd, tws, twt); + break; + } + break; case OPC_SLL_df: gen_helper_msa_sll_df(cpu_env, tdf, twd, tws, twt); break; case OPC_ADDV_df: gen_helper_msa_addv_df(cpu_env, tdf, twd, tws, twt); break; - case OPC_CEQ_df: - gen_helper_msa_ceq_df(cpu_env, tdf, twd, tws, twt); - break; case OPC_ADD_A_df: gen_helper_msa_add_a_df(cpu_env, tdf, twd, tws, twt); break; @@ -28431,9 +28722,6 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) case OPC_MAX_S_df: gen_helper_msa_max_s_df(cpu_env, tdf, twd, tws, twt); break; - case OPC_CLT_S_df: - gen_helper_msa_clt_s_df(cpu_env, tdf, twd, tws, twt); - break; case OPC_ADDS_S_df: gen_helper_msa_adds_s_df(cpu_env, tdf, twd, tws, twt); break; @@ -28449,15 +28737,9 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) case OPC_SRLR_df: gen_helper_msa_srlr_df(cpu_env, tdf, twd, tws, twt); break; - case OPC_BCLR_df: - gen_helper_msa_bclr_df(cpu_env, tdf, twd, tws, twt); - break; case OPC_MAX_U_df: gen_helper_msa_max_u_df(cpu_env, tdf, twd, tws, twt); break; - case OPC_CLT_U_df: - gen_helper_msa_clt_u_df(cpu_env, tdf, twd, tws, twt); - break; case OPC_ADDS_U_df: gen_helper_msa_adds_u_df(cpu_env, tdf, twd, tws, twt); break; @@ -28467,75 +28749,33 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx) case OPC_PCKOD_df: gen_helper_msa_pckod_df(cpu_env, tdf, twd, tws, twt); break; - case OPC_BSET_df: - gen_helper_msa_bset_df(cpu_env, tdf, twd, tws, twt); - break; case OPC_MIN_S_df: gen_helper_msa_min_s_df(cpu_env, tdf, twd, tws, twt); break; - case OPC_CLE_S_df: - gen_helper_msa_cle_s_df(cpu_env, tdf, twd, tws, twt); - break; - case OPC_AVE_S_df: - gen_helper_msa_ave_s_df(cpu_env, tdf, twd, tws, twt); - break; case OPC_ASUB_S_df: gen_helper_msa_asub_s_df(cpu_env, tdf, twd, tws, twt); break; - case OPC_DIV_S_df: - gen_helper_msa_div_s_df(cpu_env, tdf, twd, tws, twt); - break; case OPC_ILVL_df: gen_helper_msa_ilvl_df(cpu_env, tdf, twd, tws, twt); break; - case OPC_BNEG_df: - gen_helper_msa_bneg_df(cpu_env, tdf, twd, tws, twt); - break; case OPC_MIN_U_df: gen_helper_msa_min_u_df(cpu_env, tdf, twd, tws, twt); break; - case OPC_CLE_U_df: - gen_helper_msa_cle_u_df(cpu_env, tdf, twd, tws, twt); - break; - case OPC_AVE_U_df: - gen_helper_msa_ave_u_df(cpu_env, tdf, twd, tws, twt); - break; case OPC_ASUB_U_df: gen_helper_msa_asub_u_df(cpu_env, tdf, twd, tws, twt); break; - case OPC_DIV_U_df: - gen_helper_msa_div_u_df(cpu_env, tdf, twd, tws, twt); - break; case OPC_ILVR_df: gen_helper_msa_ilvr_df(cpu_env, tdf, twd, tws, twt); break; - case OPC_BINSL_df: - gen_helper_msa_binsl_df(cpu_env, tdf, twd, tws, twt); - break; case OPC_MAX_A_df: gen_helper_msa_max_a_df(cpu_env, tdf, twd, tws, twt); break; - case OPC_AVER_S_df: - gen_helper_msa_aver_s_df(cpu_env, tdf, twd, tws, twt); - break; - case OPC_MOD_S_df: - gen_helper_msa_mod_s_df(cpu_env, tdf, twd, tws, twt); - break; case OPC_ILVEV_df: gen_helper_msa_ilvev_df(cpu_env, tdf, twd, tws, twt); break; - case OPC_BINSR_df: - gen_helper_msa_binsr_df(cpu_env, tdf, twd, tws, twt); - break; case OPC_MIN_A_df: gen_helper_msa_min_a_df(cpu_env, tdf, twd, tws, twt); break; - case OPC_AVER_U_df: - gen_helper_msa_aver_u_df(cpu_env, tdf, twd, tws, twt); - break; - case OPC_MOD_U_df: - gen_helper_msa_mod_u_df(cpu_env, tdf, twd, tws, twt); - break; case OPC_ILVOD_df: gen_helper_msa_ilvod_df(cpu_env, tdf, twd, tws, twt); break; @@ -28952,14 +29192,53 @@ static void gen_msa_2r(CPUMIPSState *env, DisasContext *ctx) #endif gen_helper_msa_fill_df(cpu_env, tdf, twd, tws); /* trs */ break; - case OPC_PCNT_df: - gen_helper_msa_pcnt_df(cpu_env, tdf, twd, tws); - break; case OPC_NLOC_df: - gen_helper_msa_nloc_df(cpu_env, tdf, twd, tws); + switch (df) { + case DF_BYTE: + gen_helper_msa_nloc_b(cpu_env, twd, tws); + break; + case DF_HALF: + gen_helper_msa_nloc_h(cpu_env, twd, tws); + break; + case DF_WORD: + gen_helper_msa_nloc_w(cpu_env, twd, tws); + break; + case DF_DOUBLE: + gen_helper_msa_nloc_d(cpu_env, twd, tws); + break; + } break; case OPC_NLZC_df: - gen_helper_msa_nlzc_df(cpu_env, tdf, twd, tws); + switch (df) { + case DF_BYTE: + gen_helper_msa_nlzc_b(cpu_env, twd, tws); + break; + case DF_HALF: + gen_helper_msa_nlzc_h(cpu_env, twd, tws); + break; + case DF_WORD: + gen_helper_msa_nlzc_w(cpu_env, twd, tws); + break; + case DF_DOUBLE: + gen_helper_msa_nlzc_d(cpu_env, twd, tws); + break; + } + break; + case OPC_PCNT_df: + switch (df) { + case DF_BYTE: + gen_helper_msa_pcnt_b(cpu_env, twd, tws); + break; + case DF_HALF: + gen_helper_msa_pcnt_h(cpu_env, twd, tws); + break; + case DF_WORD: + gen_helper_msa_pcnt_w(cpu_env, twd, tws); + break; + case DF_DOUBLE: + gen_helper_msa_pcnt_d(cpu_env, twd, tws); + break; + } break; default: MIPS_INVAL("MSA instruction"); diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index eaee1a5575..e3e82327b7 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -235,6 +235,7 @@ typedef union _ppc_vsr_t { } ppc_vsr_t; typedef ppc_vsr_t ppc_avr_t; +typedef ppc_vsr_t ppc_fprp_t; #if !defined(CONFIG_USER_ONLY) /* Software TLB cache */ @@ -559,6 +560,9 @@ enum { /*****************************************************************************/ /* Floating point status and control register */ +#define FPSCR_DRN2 34 /* Decimal Floating-Point rounding control */ +#define FPSCR_DRN1 33 /* Decimal Floating-Point rounding control */ +#define FPSCR_DRN0 32 /* Decimal Floating-Point rounding control */ #define FPSCR_FX 31 /* Floating-point exception summary */ #define FPSCR_FEX 30 /* Floating-point enabled exception summary */ #define FPSCR_VX 29 /* Floating-point invalid operation exception summ. */ @@ -592,6 +596,7 @@ enum { #define FPSCR_NI 2 /* Floating-point non-IEEE mode */ #define FPSCR_RN1 1 #define FPSCR_RN0 0 /* Floating-point rounding control */ +#define fpscr_drn (((env->fpscr) & FP_DRN) >> FPSCR_DRN0) #define fpscr_fex (((env->fpscr) >> FPSCR_FEX) & 0x1) #define fpscr_vx (((env->fpscr) >> FPSCR_VX) & 0x1) #define fpscr_ox (((env->fpscr) >> FPSCR_OX) & 0x1) @@ -627,6 +632,10 @@ enum { #define fpscr_eex (((env->fpscr) >> FPSCR_XX) & ((env->fpscr) >> FPSCR_XE) & \ 0x1F) +#define FP_DRN2 (1ull << FPSCR_DRN2) +#define FP_DRN1 (1ull << FPSCR_DRN1) +#define FP_DRN0 (1ull << FPSCR_DRN0) +#define FP_DRN (FP_DRN2 | FP_DRN1 | FP_DRN0) #define FP_FX (1ull << FPSCR_FX) #define FP_FEX (1ull << FPSCR_FEX) #define FP_VX (1ull << FPSCR_VX) @@ -662,7 +671,6 @@ enum { #define FP_RN0 (1ull << FPSCR_RN0) #define FP_RN (FP_RN1 | FP_RN0) -#define FP_MODE FP_RN #define FP_ENABLES (FP_VE | FP_OE | FP_UE | FP_ZE | FP_XE) #define FP_STATUS (FP_FR | FP_FI | FP_FPRF) diff --git a/target/ppc/dfp_helper.c b/target/ppc/dfp_helper.c index f102177572..2c65badae4 100644 --- a/target/ppc/dfp_helper.c +++ b/target/ppc/dfp_helper.c @@ -28,17 +28,32 @@ #include "libdecnumber/dpd/decimal64.h" #include "libdecnumber/dpd/decimal128.h" -#if defined(HOST_WORDS_BIGENDIAN) -#define HI_IDX 0 -#define LO_IDX 1 -#else -#define HI_IDX 1 -#define LO_IDX 0 -#endif + +static void get_dfp64(ppc_vsr_t *dst, ppc_fprp_t *dfp) +{ + dst->VsrD(1) = dfp->VsrD(0); +} + +static void get_dfp128(ppc_vsr_t *dst, ppc_fprp_t *dfp) +{ + dst->VsrD(0) = dfp[0].VsrD(0); + dst->VsrD(1) = dfp[1].VsrD(0); +} + +static void set_dfp64(ppc_fprp_t *dfp, ppc_vsr_t *src) +{ + dfp->VsrD(0) = src->VsrD(1); +} + +static void set_dfp128(ppc_fprp_t *dfp, ppc_vsr_t *src) +{ + dfp[0].VsrD(0) = src->VsrD(0); + dfp[1].VsrD(0) = src->VsrD(1); +} struct PPC_DFP { CPUPPCState *env; - uint64_t t64[2], a64[2], b64[2]; + ppc_vsr_t vt, va, vb; decNumber t, a, b; decContext context; uint8_t crbf; @@ -48,7 +63,7 @@ static void dfp_prepare_rounding_mode(decContext *context, uint64_t fpscr) { enum rounding rnd; - switch ((fpscr >> 32) & 0x7) { + switch ((fpscr & FP_DRN) >> FPSCR_DRN0) { case 0: rnd = DEC_ROUND_HALF_EVEN; break; @@ -121,56 +136,64 @@ static void dfp_set_round_mode_from_immediate(uint8_t r, uint8_t rmc, decContextSetRounding(&dfp->context, rnd); } -static void dfp_prepare_decimal64(struct PPC_DFP *dfp, uint64_t *a, - uint64_t *b, CPUPPCState *env) +static void dfp_prepare_decimal64(struct PPC_DFP *dfp, ppc_fprp_t *a, + ppc_fprp_t *b, CPUPPCState *env) { decContextDefault(&dfp->context, DEC_INIT_DECIMAL64); dfp_prepare_rounding_mode(&dfp->context, env->fpscr); dfp->env = env; if (a) { - dfp->a64[0] = *a; - decimal64ToNumber((decimal64 *)dfp->a64, &dfp->a); + get_dfp64(&dfp->va, a); + decimal64ToNumber((decimal64 *)&dfp->va.VsrD(1), &dfp->a); } else { - dfp->a64[0] = 0; + dfp->va.VsrD(1) = 0; decNumberZero(&dfp->a); } if (b) { - dfp->b64[0] = *b; - decimal64ToNumber((decimal64 *)dfp->b64, &dfp->b); + get_dfp64(&dfp->vb, b); + decimal64ToNumber((decimal64 *)&dfp->vb.VsrD(1), &dfp->b); } else { - dfp->b64[0] = 0; + dfp->vb.VsrD(1) = 0; decNumberZero(&dfp->b); } } -static void dfp_prepare_decimal128(struct PPC_DFP *dfp, uint64_t *a, - uint64_t *b, CPUPPCState *env) +static void dfp_prepare_decimal128(struct PPC_DFP *dfp, ppc_fprp_t *a, + ppc_fprp_t *b, CPUPPCState *env) { decContextDefault(&dfp->context, DEC_INIT_DECIMAL128); dfp_prepare_rounding_mode(&dfp->context, env->fpscr); dfp->env = env; if (a) { - dfp->a64[0] = a[HI_IDX]; - dfp->a64[1] = a[LO_IDX]; - decimal128ToNumber((decimal128 *)dfp->a64, &dfp->a); + get_dfp128(&dfp->va, a); + decimal128ToNumber((decimal128 *)&dfp->va, &dfp->a); } else { - dfp->a64[0] = dfp->a64[1] = 0; + dfp->va.VsrD(0) = dfp->va.VsrD(1) = 0; decNumberZero(&dfp->a); } if (b) { - dfp->b64[0] = b[HI_IDX]; - dfp->b64[1] = b[LO_IDX]; - decimal128ToNumber((decimal128 *)dfp->b64, &dfp->b); + get_dfp128(&dfp->vb, b); + decimal128ToNumber((decimal128 *)&dfp->vb, &dfp->b); } else { - dfp->b64[0] = dfp->b64[1] = 0; + dfp->vb.VsrD(0) = dfp->vb.VsrD(1) = 0; decNumberZero(&dfp->b); } } +static void dfp_finalize_decimal64(struct PPC_DFP *dfp) +{ + decimal64FromNumber((decimal64 *)&dfp->vt.VsrD(1), &dfp->t, &dfp->context); +} + +static void dfp_finalize_decimal128(struct PPC_DFP *dfp) +{ + decimal128FromNumber((decimal128 *)&dfp->vt, &dfp->t, &dfp->context); +} + static void dfp_set_FPSCR_flag(struct PPC_DFP *dfp, uint64_t flag, uint64_t enabled) { @@ -220,8 +243,8 @@ static void dfp_set_FPRF_from_FRT_with_context(struct PPC_DFP *dfp, default: assert(0); /* should never get here */ } - dfp->env->fpscr &= ~(0x1F << 12); - dfp->env->fpscr |= (fprf << 12); + dfp->env->fpscr &= ~FP_FPRF; + dfp->env->fpscr |= (fprf << FPSCR_FPRF); } static void dfp_set_FPRF_from_FRT(struct PPC_DFP *dfp) @@ -369,8 +392,8 @@ static void dfp_set_CRBF_from_T(struct PPC_DFP *dfp) static void dfp_set_FPCC_from_CRBF(struct PPC_DFP *dfp) { - dfp->env->fpscr &= ~(0xF << 12); - dfp->env->fpscr |= (dfp->crbf << 12); + dfp->env->fpscr &= ~FP_FPCC; + dfp->env->fpscr |= (dfp->crbf << FPSCR_FPCC); } static inline void dfp_makeQNaN(decNumber *dn) @@ -396,19 +419,15 @@ static inline int dfp_get_digit(decNumber *dn, int n) } #define DFP_HELPER_TAB(op, dnop, postprocs, size) \ -void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b) \ +void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ + ppc_fprp_t *b) \ { \ struct PPC_DFP dfp; \ dfp_prepare_decimal##size(&dfp, a, b, env); \ dnop(&dfp.t, &dfp.a, &dfp.b, &dfp.context); \ - decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \ + dfp_finalize_decimal##size(&dfp); \ postprocs(&dfp); \ - if (size == 64) { \ - t[0] = dfp.t64[0]; \ - } else if (size == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ - } \ + set_dfp##size(t, &dfp.vt); \ } static void ADD_PPs(struct PPC_DFP *dfp) @@ -466,12 +485,12 @@ DFP_HELPER_TAB(ddiv, decNumberDivide, DIV_PPs, 64) DFP_HELPER_TAB(ddivq, decNumberDivide, DIV_PPs, 128) #define DFP_HELPER_BF_AB(op, dnop, postprocs, size) \ -uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint64_t *b) \ +uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, ppc_fprp_t *b) \ { \ struct PPC_DFP dfp; \ dfp_prepare_decimal##size(&dfp, a, b, env); \ dnop(&dfp.t, &dfp.a, &dfp.b, &dfp.context); \ - decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \ + dfp_finalize_decimal##size(&dfp); \ postprocs(&dfp); \ return dfp.crbf; \ } @@ -498,7 +517,7 @@ DFP_HELPER_BF_AB(dcmpo, decNumberCompare, CMPO_PPs, 64) DFP_HELPER_BF_AB(dcmpoq, decNumberCompare, CMPO_PPs, 128) #define DFP_HELPER_TSTDC(op, size) \ -uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint32_t dcm) \ +uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, uint32_t dcm) \ { \ struct PPC_DFP dfp; \ int match = 0; \ @@ -526,7 +545,7 @@ DFP_HELPER_TSTDC(dtstdc, 64) DFP_HELPER_TSTDC(dtstdcq, 128) #define DFP_HELPER_TSTDG(op, size) \ -uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint32_t dcm) \ +uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, uint32_t dcm) \ { \ struct PPC_DFP dfp; \ int minexp, maxexp, nzero_digits, nzero_idx, is_negative, is_zero, \ @@ -581,7 +600,7 @@ DFP_HELPER_TSTDG(dtstdg, 64) DFP_HELPER_TSTDG(dtstdgq, 128) #define DFP_HELPER_TSTEX(op, size) \ -uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint64_t *b) \ +uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, ppc_fprp_t *b) \ { \ struct PPC_DFP dfp; \ int expa, expb, a_is_special, b_is_special; \ @@ -613,14 +632,16 @@ DFP_HELPER_TSTEX(dtstex, 64) DFP_HELPER_TSTEX(dtstexq, 128) #define DFP_HELPER_TSTSF(op, size) \ -uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint64_t *b) \ +uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, ppc_fprp_t *b) \ { \ struct PPC_DFP dfp; \ unsigned k; \ + ppc_vsr_t va; \ \ dfp_prepare_decimal##size(&dfp, 0, b, env); \ \ - k = *a & 0x3F; \ + get_dfp64(&va, a); \ + k = va.VsrD(1) & 0x3F; \ \ if (unlikely(decNumberIsSpecial(&dfp.b))) { \ dfp.crbf = 1; \ @@ -648,7 +669,7 @@ DFP_HELPER_TSTSF(dtstsf, 64) DFP_HELPER_TSTSF(dtstsfq, 128) #define DFP_HELPER_TSTSFI(op, size) \ -uint32_t helper_##op(CPUPPCState *env, uint32_t a, uint64_t *b) \ +uint32_t helper_##op(CPUPPCState *env, uint32_t a, ppc_fprp_t *b) \ { \ struct PPC_DFP dfp; \ unsigned uim; \ @@ -708,7 +729,7 @@ static void dfp_quantize(uint8_t rmc, struct PPC_DFP *dfp) } #define DFP_HELPER_QUAI(op, size) \ -void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, \ +void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ uint32_t te, uint32_t rmc) \ { \ struct PPC_DFP dfp; \ @@ -719,40 +740,28 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, \ dfp.a.exponent = (int32_t)((int8_t)(te << 3) >> 3); \ \ dfp_quantize(rmc, &dfp); \ - decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ - &dfp.context); \ + dfp_finalize_decimal##size(&dfp); \ QUA_PPs(&dfp); \ \ - if (size == 64) { \ - t[0] = dfp.t64[0]; \ - } else if (size == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ - } \ + set_dfp##size(t, &dfp.vt); \ } DFP_HELPER_QUAI(dquai, 64) DFP_HELPER_QUAI(dquaiq, 128) #define DFP_HELPER_QUA(op, size) \ -void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, \ - uint64_t *b, uint32_t rmc) \ +void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ + ppc_fprp_t *b, uint32_t rmc) \ { \ struct PPC_DFP dfp; \ \ dfp_prepare_decimal##size(&dfp, a, b, env); \ \ dfp_quantize(rmc, &dfp); \ - decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ - &dfp.context); \ + dfp_finalize_decimal##size(&dfp); \ QUA_PPs(&dfp); \ \ - if (size == 64) { \ - t[0] = dfp.t64[0]; \ - } else if (size == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ - } \ + set_dfp##size(t, &dfp.vt); \ } DFP_HELPER_QUA(dqua, 64) @@ -813,33 +822,31 @@ static void _dfp_reround(uint8_t rmc, int32_t ref_sig, int32_t xmax, } #define DFP_HELPER_RRND(op, size) \ -void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, \ - uint64_t *b, uint32_t rmc) \ +void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ + ppc_fprp_t *b, uint32_t rmc) \ { \ struct PPC_DFP dfp; \ - int32_t ref_sig = *a & 0x3F; \ + ppc_vsr_t va; \ + int32_t ref_sig; \ int32_t xmax = ((size) == 64) ? 369 : 6111; \ \ dfp_prepare_decimal##size(&dfp, 0, b, env); \ \ + get_dfp64(&va, a); \ + ref_sig = va.VsrD(1) & 0x3f; \ + \ _dfp_reround(rmc, ref_sig, xmax, &dfp); \ - decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ - &dfp.context); \ + dfp_finalize_decimal##size(&dfp); \ QUA_PPs(&dfp); \ \ - if (size == 64) { \ - t[0] = dfp.t64[0]; \ - } else if (size == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ - } \ + set_dfp##size(t, &dfp.vt); \ } DFP_HELPER_RRND(drrnd, 64) DFP_HELPER_RRND(drrndq, 128) #define DFP_HELPER_RINT(op, postprocs, size) \ -void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, \ +void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ uint32_t r, uint32_t rmc) \ { \ struct PPC_DFP dfp; \ @@ -848,15 +855,10 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, \ \ dfp_set_round_mode_from_immediate(r, rmc, &dfp); \ decNumberToIntegralExact(&dfp.t, &dfp.b, &dfp.context); \ - decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \ + dfp_finalize_decimal##size(&dfp); \ postprocs(&dfp); \ \ - if (size == 64) { \ - t[0] = dfp.t64[0]; \ - } else if (size == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ - } \ + set_dfp##size(t, &dfp.vt); \ } static void RINTX_PPs(struct PPC_DFP *dfp) @@ -878,34 +880,42 @@ static void RINTN_PPs(struct PPC_DFP *dfp) DFP_HELPER_RINT(drintn, RINTN_PPs, 64) DFP_HELPER_RINT(drintnq, RINTN_PPs, 128) -void helper_dctdp(CPUPPCState *env, uint64_t *t, uint64_t *b) +void helper_dctdp(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) { struct PPC_DFP dfp; - uint32_t b_short = *b; + ppc_vsr_t vb; + uint32_t b_short; + + get_dfp64(&vb, b); + b_short = (uint32_t)vb.VsrD(1); + dfp_prepare_decimal64(&dfp, 0, 0, env); decimal32ToNumber((decimal32 *)&b_short, &dfp.t); - decimal64FromNumber((decimal64 *)t, &dfp.t, &dfp.context); + dfp_finalize_decimal64(&dfp); + set_dfp64(t, &dfp.vt); dfp_set_FPRF_from_FRT(&dfp); } -void helper_dctqpq(CPUPPCState *env, uint64_t *t, uint64_t *b) +void helper_dctqpq(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) { struct PPC_DFP dfp; + ppc_vsr_t vb; dfp_prepare_decimal128(&dfp, 0, 0, env); - decimal64ToNumber((decimal64 *)b, &dfp.t); + get_dfp64(&vb, b); + decimal64ToNumber((decimal64 *)&vb.VsrD(1), &dfp.t); dfp_check_for_VXSNAN_and_convert_to_QNaN(&dfp); dfp_set_FPRF_from_FRT(&dfp); - decimal128FromNumber((decimal128 *)&dfp.t64, &dfp.t, &dfp.context); - t[0] = dfp.t64[HI_IDX]; - t[1] = dfp.t64[LO_IDX]; + dfp_finalize_decimal128(&dfp); + set_dfp128(t, &dfp.vt); } -void helper_drsp(CPUPPCState *env, uint64_t *t, uint64_t *b) +void helper_drsp(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) { struct PPC_DFP dfp; uint32_t t_short = 0; + ppc_vsr_t vt; dfp_prepare_decimal64(&dfp, 0, b, env); decimal32FromNumber((decimal32 *)&t_short, &dfp.b, &dfp.context); decimal32ToNumber((decimal32 *)&t_short, &dfp.t); @@ -915,15 +925,16 @@ void helper_drsp(CPUPPCState *env, uint64_t *t, uint64_t *b) dfp_check_for_UX(&dfp); dfp_check_for_XX(&dfp); - *t = t_short; + vt.VsrD(1) = (uint64_t)t_short; + set_dfp64(t, &vt); } -void helper_drdpq(CPUPPCState *env, uint64_t *t, uint64_t *b) +void helper_drdpq(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) { struct PPC_DFP dfp; dfp_prepare_decimal128(&dfp, 0, b, env); - decimal64FromNumber((decimal64 *)&dfp.t64, &dfp.b, &dfp.context); - decimal64ToNumber((decimal64 *)&dfp.t64, &dfp.t); + decimal64FromNumber((decimal64 *)&dfp.vt.VsrD(1), &dfp.b, &dfp.context); + decimal64ToNumber((decimal64 *)&dfp.vt.VsrD(1), &dfp.t); dfp_check_for_VXSNAN_and_convert_to_QNaN(&dfp); dfp_set_FPRF_from_FRT_long(&dfp); @@ -931,26 +942,23 @@ void helper_drdpq(CPUPPCState *env, uint64_t *t, uint64_t *b) dfp_check_for_UX(&dfp); dfp_check_for_XX(&dfp); - decimal64FromNumber((decimal64 *)dfp.t64, &dfp.t, &dfp.context); - t[0] = dfp.t64[0]; - t[1] = 0; + dfp.vt.VsrD(0) = dfp.vt.VsrD(1) = 0; + dfp_finalize_decimal64(&dfp); + set_dfp128(t, &dfp.vt); } #define DFP_HELPER_CFFIX(op, size) \ -void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b) \ +void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) \ { \ struct PPC_DFP dfp; \ + ppc_vsr_t vb; \ dfp_prepare_decimal##size(&dfp, 0, b, env); \ - decNumberFromInt64(&dfp.t, (int64_t)(*b)); \ - decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \ + get_dfp64(&vb, b); \ + decNumberFromInt64(&dfp.t, (int64_t)vb.VsrD(1)); \ + dfp_finalize_decimal##size(&dfp); \ CFFIX_PPs(&dfp); \ \ - if (size == 64) { \ - t[0] = dfp.t64[0]; \ - } else if (size == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ - } \ + set_dfp##size(t, &dfp.vt); \ } static void CFFIX_PPs(struct PPC_DFP *dfp) @@ -963,7 +971,7 @@ DFP_HELPER_CFFIX(dcffix, 64) DFP_HELPER_CFFIX(dcffixq, 128) #define DFP_HELPER_CTFIX(op, size) \ -void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b) \ +void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) \ { \ struct PPC_DFP dfp; \ dfp_prepare_decimal##size(&dfp, 0, b, env); \ @@ -971,62 +979,65 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b) \ if (unlikely(decNumberIsSpecial(&dfp.b))) { \ uint64_t invalid_flags = FP_VX | FP_VXCVI; \ if (decNumberIsInfinite(&dfp.b)) { \ - dfp.t64[0] = decNumberIsNegative(&dfp.b) ? INT64_MIN : INT64_MAX; \ + dfp.vt.VsrD(1) = decNumberIsNegative(&dfp.b) ? INT64_MIN : \ + INT64_MAX; \ } else { /* NaN */ \ - dfp.t64[0] = INT64_MIN; \ + dfp.vt.VsrD(1) = INT64_MIN; \ if (decNumberIsSNaN(&dfp.b)) { \ invalid_flags |= FP_VXSNAN; \ } \ } \ dfp_set_FPSCR_flag(&dfp, invalid_flags, FP_VE); \ } else if (unlikely(decNumberIsZero(&dfp.b))) { \ - dfp.t64[0] = 0; \ + dfp.vt.VsrD(1) = 0; \ } else { \ decNumberToIntegralExact(&dfp.b, &dfp.b, &dfp.context); \ - dfp.t64[0] = decNumberIntegralToInt64(&dfp.b, &dfp.context); \ + dfp.vt.VsrD(1) = decNumberIntegralToInt64(&dfp.b, &dfp.context); \ if (decContextTestStatus(&dfp.context, DEC_Invalid_operation)) { \ - dfp.t64[0] = decNumberIsNegative(&dfp.b) ? INT64_MIN : INT64_MAX; \ + dfp.vt.VsrD(1) = decNumberIsNegative(&dfp.b) ? INT64_MIN : \ + INT64_MAX; \ dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FP_VE); \ } else { \ dfp_check_for_XX(&dfp); \ } \ } \ \ - *t = dfp.t64[0]; \ + set_dfp64(t, &dfp.vt); \ } DFP_HELPER_CTFIX(dctfix, 64) DFP_HELPER_CTFIX(dctfixq, 128) -static inline void dfp_set_bcd_digit_64(uint64_t *t, uint8_t digit, - unsigned n) +static inline void dfp_set_bcd_digit_64(ppc_vsr_t *t, uint8_t digit, + unsigned n) { - *t |= ((uint64_t)(digit & 0xF) << (n << 2)); + t->VsrD(1) |= ((uint64_t)(digit & 0xF) << (n << 2)); } -static inline void dfp_set_bcd_digit_128(uint64_t *t, uint8_t digit, - unsigned n) +static inline void dfp_set_bcd_digit_128(ppc_vsr_t *t, uint8_t digit, + unsigned n) { - t[(n & 0x10) ? HI_IDX : LO_IDX] |= + t->VsrD((n & 0x10) ? 0 : 1) |= ((uint64_t)(digit & 0xF) << ((n & 15) << 2)); } -static inline void dfp_set_sign_64(uint64_t *t, uint8_t sgn) +static inline void dfp_set_sign_64(ppc_vsr_t *t, uint8_t sgn) { - *t <<= 4; - *t |= (sgn & 0xF); + t->VsrD(1) <<= 4; + t->VsrD(1) |= (sgn & 0xF); } -static inline void dfp_set_sign_128(uint64_t *t, uint8_t sgn) +static inline void dfp_set_sign_128(ppc_vsr_t *t, uint8_t sgn) { - t[HI_IDX] <<= 4; - t[HI_IDX] |= (t[LO_IDX] >> 60); - t[LO_IDX] <<= 4; - t[LO_IDX] |= (sgn & 0xF); + t->VsrD(0) <<= 4; + t->VsrD(0) |= (t->VsrD(1) >> 60); + t->VsrD(1) <<= 4; + t->VsrD(1) |= (sgn & 0xF); } #define DFP_HELPER_DEDPD(op, size) \ -void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t sp) \ +void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ + uint32_t sp) \ { \ struct PPC_DFP dfp; \ uint8_t digits[34]; \ @@ -1035,11 +1046,11 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t sp) \ dfp_prepare_decimal##size(&dfp, 0, b, env); \ \ decNumberGetBCD(&dfp.b, digits); \ - dfp.t64[0] = dfp.t64[1] = 0; \ + dfp.vt.VsrD(0) = dfp.vt.VsrD(1) = 0; \ N = dfp.b.digits; \ \ for (i = 0; (i < N) && (i < (size)/4); i++) { \ - dfp_set_bcd_digit_##size(dfp.t64, digits[N-i-1], i); \ + dfp_set_bcd_digit_##size(&dfp.vt, digits[N - i - 1], i); \ } \ \ if (sp & 2) { \ @@ -1050,32 +1061,28 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t sp) \ } else { \ sgn = ((sp & 1) ? 0xF : 0xC); \ } \ - dfp_set_sign_##size(dfp.t64, sgn); \ + dfp_set_sign_##size(&dfp.vt, sgn); \ } \ \ - if (size == 64) { \ - t[0] = dfp.t64[0]; \ - } else if (size == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ - } \ + set_dfp##size(t, &dfp.vt); \ } DFP_HELPER_DEDPD(ddedpd, 64) DFP_HELPER_DEDPD(ddedpdq, 128) -static inline uint8_t dfp_get_bcd_digit_64(uint64_t *t, unsigned n) +static inline uint8_t dfp_get_bcd_digit_64(ppc_vsr_t *t, unsigned n) { - return *t >> ((n << 2) & 63) & 15; + return t->VsrD(1) >> ((n << 2) & 63) & 15; } -static inline uint8_t dfp_get_bcd_digit_128(uint64_t *t, unsigned n) +static inline uint8_t dfp_get_bcd_digit_128(ppc_vsr_t *t, unsigned n) { - return t[(n & 0x10) ? HI_IDX : LO_IDX] >> ((n << 2) & 63) & 15; + return t->VsrD((n & 0x10) ? 0 : 1) >> ((n << 2) & 63) & 15; } #define DFP_HELPER_ENBCD(op, size) \ -void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t s) \ +void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \ + uint32_t s) \ { \ struct PPC_DFP dfp; \ uint8_t digits[32]; \ @@ -1086,7 +1093,7 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t s) \ decNumberZero(&dfp.t); \ \ if (s) { \ - uint8_t sgnNibble = dfp_get_bcd_digit_##size(dfp.b64, offset++); \ + uint8_t sgnNibble = dfp_get_bcd_digit_##size(&dfp.vb, offset++); \ switch (sgnNibble) { \ case 0xD: \ case 0xB: \ @@ -1106,7 +1113,8 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t s) \ \ while (offset < (size) / 4) { \ n++; \ - digits[(size) / 4 - n] = dfp_get_bcd_digit_##size(dfp.b64, offset++); \ + digits[(size) / 4 - n] = dfp_get_bcd_digit_##size(&dfp.vb, \ + offset++); \ if (digits[(size) / 4 - n] > 10) { \ dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FPSCR_VE); \ return; \ @@ -1122,71 +1130,72 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t s) \ if (s && sgn) { \ dfp.t.bits |= DECNEG; \ } \ - decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ - &dfp.context); \ + dfp_finalize_decimal##size(&dfp); \ dfp_set_FPRF_from_FRT(&dfp); \ - if ((size) == 64) { \ - t[0] = dfp.t64[0]; \ - } else if ((size) == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ - } \ + set_dfp##size(t, &dfp.vt); \ } DFP_HELPER_ENBCD(denbcd, 64) DFP_HELPER_ENBCD(denbcdq, 128) #define DFP_HELPER_XEX(op, size) \ -void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b) \ +void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) \ { \ struct PPC_DFP dfp; \ + ppc_vsr_t vt; \ \ dfp_prepare_decimal##size(&dfp, 0, b, env); \ \ if (unlikely(decNumberIsSpecial(&dfp.b))) { \ if (decNumberIsInfinite(&dfp.b)) { \ - *t = -1; \ + vt.VsrD(1) = -1; \ } else if (decNumberIsSNaN(&dfp.b)) { \ - *t = -3; \ + vt.VsrD(1) = -3; \ } else if (decNumberIsQNaN(&dfp.b)) { \ - *t = -2; \ + vt.VsrD(1) = -2; \ } else { \ assert(0); \ } \ + set_dfp64(t, &vt); \ } else { \ if ((size) == 64) { \ - *t = dfp.b.exponent + 398; \ + vt.VsrD(1) = dfp.b.exponent + 398; \ } else if ((size) == 128) { \ - *t = dfp.b.exponent + 6176; \ + vt.VsrD(1) = dfp.b.exponent + 6176; \ } else { \ assert(0); \ } \ + set_dfp64(t, &vt); \ } \ } DFP_HELPER_XEX(dxex, 64) DFP_HELPER_XEX(dxexq, 128) -static void dfp_set_raw_exp_64(uint64_t *t, uint64_t raw) +static void dfp_set_raw_exp_64(ppc_vsr_t *t, uint64_t raw) { - *t &= 0x8003ffffffffffffULL; - *t |= (raw << (63 - 13)); + t->VsrD(1) &= 0x8003ffffffffffffULL; + t->VsrD(1) |= (raw << (63 - 13)); } -static void dfp_set_raw_exp_128(uint64_t *t, uint64_t raw) +static void dfp_set_raw_exp_128(ppc_vsr_t *t, uint64_t raw) { - t[HI_IDX] &= 0x80003fffffffffffULL; - t[HI_IDX] |= (raw << (63 - 17)); + t->VsrD(0) &= 0x80003fffffffffffULL; + t->VsrD(0) |= (raw << (63 - 17)); } #define DFP_HELPER_IEX(op, size) \ -void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b) \ +void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ + ppc_fprp_t *b) \ { \ struct PPC_DFP dfp; \ uint64_t raw_qnan, raw_snan, raw_inf, max_exp; \ + ppc_vsr_t va; \ int bias; \ - int64_t exp = *((int64_t *)a); \ + int64_t exp; \ \ + get_dfp64(&va, a); \ + exp = (int64_t)va.VsrD(1); \ dfp_prepare_decimal##size(&dfp, 0, b, env); \ \ if ((size) == 64) { \ @@ -1206,14 +1215,14 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b) \ } \ \ if (unlikely((exp < 0) || (exp > max_exp))) { \ - dfp.t64[0] = dfp.b64[0]; \ - dfp.t64[1] = dfp.b64[1]; \ + dfp.vt.VsrD(0) = dfp.vb.VsrD(0); \ + dfp.vt.VsrD(1) = dfp.vb.VsrD(1); \ if (exp == -1) { \ - dfp_set_raw_exp_##size(dfp.t64, raw_inf); \ + dfp_set_raw_exp_##size(&dfp.vt, raw_inf); \ } else if (exp == -3) { \ - dfp_set_raw_exp_##size(dfp.t64, raw_snan); \ + dfp_set_raw_exp_##size(&dfp.vt, raw_snan); \ } else { \ - dfp_set_raw_exp_##size(dfp.t64, raw_qnan); \ + dfp_set_raw_exp_##size(&dfp.vt, raw_qnan); \ } \ } else { \ dfp.t = dfp.b; \ @@ -1221,15 +1230,9 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b) \ dfp.t.bits &= ~DECSPECIAL; \ } \ dfp.t.exponent = exp - bias; \ - decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ - &dfp.context); \ - } \ - if (size == 64) { \ - t[0] = dfp.t64[0]; \ - } else if (size == 128) { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ + dfp_finalize_decimal##size(&dfp); \ } \ + set_dfp##size(t, &dfp.vt); \ } DFP_HELPER_IEX(diex, 64) @@ -1276,7 +1279,7 @@ static void dfp_clear_lmd_from_g5msb(uint64_t *t) } #define DFP_HELPER_SHIFT(op, size, shift_left) \ -void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, \ +void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \ uint32_t sh) \ { \ struct PPC_DFP dfp; \ @@ -1303,26 +1306,21 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, \ dfp.t.digits = max_digits - 1; \ } \ \ - decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ - &dfp.context); \ + dfp_finalize_decimal##size(&dfp); \ } else { \ if ((size) == 64) { \ - dfp.t64[0] = dfp.a64[0] & 0xFFFC000000000000ULL; \ - dfp_clear_lmd_from_g5msb(dfp.t64); \ + dfp.vt.VsrD(1) = dfp.va.VsrD(1) & \ + 0xFFFC000000000000ULL; \ + dfp_clear_lmd_from_g5msb(&dfp.vt.VsrD(1)); \ } else { \ - dfp.t64[HI_IDX] = dfp.a64[HI_IDX] & \ - 0xFFFFC00000000000ULL; \ - dfp_clear_lmd_from_g5msb(dfp.t64 + HI_IDX); \ - dfp.t64[LO_IDX] = 0; \ + dfp.vt.VsrD(0) = dfp.va.VsrD(0) & \ + 0xFFFFC00000000000ULL; \ + dfp_clear_lmd_from_g5msb(&dfp.vt.VsrD(0)); \ + dfp.vt.VsrD(1) = 0; \ } \ } \ \ - if ((size) == 64) { \ - t[0] = dfp.t64[0]; \ - } else { \ - t[0] = dfp.t64[HI_IDX]; \ - t[1] = dfp.t64[LO_IDX]; \ - } \ + set_dfp##size(t, &dfp.vt); \ } DFP_HELPER_SHIFT(dscli, 64, 1) diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index 4b1a2e6178..dc383242f7 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -180,7 +180,7 @@ static void set_fprf_from_class(CPUPPCState *env, int class) }; bool isneg = class & is_neg; - env->fpscr &= ~(0x1F << FPSCR_FPRF); + env->fpscr &= ~FP_FPRF; env->fpscr |= fprf[ctz32(class)][isneg] << FPSCR_FPRF; } @@ -199,12 +199,12 @@ COMPUTE_FPRF(float128) static void finish_invalid_op_excp(CPUPPCState *env, int op, uintptr_t retaddr) { /* Update the floating-point invalid operation summary */ - env->fpscr |= 1 << FPSCR_VX; + env->fpscr |= FP_VX; /* Update the floating-point exception summary */ env->fpscr |= FP_FX; if (fpscr_ve != 0) { /* Update the floating-point enabled exception summary */ - env->fpscr |= 1 << FPSCR_FEX; + env->fpscr |= FP_FEX; if (fp_exceptions_enabled(env)) { raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | op, retaddr); @@ -215,11 +215,11 @@ static void finish_invalid_op_excp(CPUPPCState *env, int op, uintptr_t retaddr) static void finish_invalid_op_arith(CPUPPCState *env, int op, bool set_fpcc, uintptr_t retaddr) { - env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); + env->fpscr &= ~(FP_FR | FP_FI); if (fpscr_ve == 0) { if (set_fpcc) { - env->fpscr &= ~(0xF << FPSCR_FPCC); - env->fpscr |= 0x11 << FPSCR_FPCC; + env->fpscr &= ~FP_FPCC; + env->fpscr |= (FP_C | FP_FU); } } finish_invalid_op_excp(env, op, retaddr); @@ -228,7 +228,7 @@ static void finish_invalid_op_arith(CPUPPCState *env, int op, /* Signalling NaN */ static void float_invalid_op_vxsnan(CPUPPCState *env, uintptr_t retaddr) { - env->fpscr |= 1 << FPSCR_VXSNAN; + env->fpscr |= FP_VXSNAN; finish_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, retaddr); } @@ -236,7 +236,7 @@ static void float_invalid_op_vxsnan(CPUPPCState *env, uintptr_t retaddr) static void float_invalid_op_vxisi(CPUPPCState *env, bool set_fpcc, uintptr_t retaddr) { - env->fpscr |= 1 << FPSCR_VXISI; + env->fpscr |= FP_VXISI; finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXISI, set_fpcc, retaddr); } @@ -244,7 +244,7 @@ static void float_invalid_op_vxisi(CPUPPCState *env, bool set_fpcc, static void float_invalid_op_vxidi(CPUPPCState *env, bool set_fpcc, uintptr_t retaddr) { - env->fpscr |= 1 << FPSCR_VXIDI; + env->fpscr |= FP_VXIDI; finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXIDI, set_fpcc, retaddr); } @@ -252,7 +252,7 @@ static void float_invalid_op_vxidi(CPUPPCState *env, bool set_fpcc, static void float_invalid_op_vxzdz(CPUPPCState *env, bool set_fpcc, uintptr_t retaddr) { - env->fpscr |= 1 << FPSCR_VXZDZ; + env->fpscr |= FP_VXZDZ; finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXZDZ, set_fpcc, retaddr); } @@ -260,7 +260,7 @@ static void float_invalid_op_vxzdz(CPUPPCState *env, bool set_fpcc, static void float_invalid_op_vximz(CPUPPCState *env, bool set_fpcc, uintptr_t retaddr) { - env->fpscr |= 1 << FPSCR_VXIMZ; + env->fpscr |= FP_VXIMZ; finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXIMZ, set_fpcc, retaddr); } @@ -268,7 +268,7 @@ static void float_invalid_op_vximz(CPUPPCState *env, bool set_fpcc, static void float_invalid_op_vxsqrt(CPUPPCState *env, bool set_fpcc, uintptr_t retaddr) { - env->fpscr |= 1 << FPSCR_VXSQRT; + env->fpscr |= FP_VXSQRT; finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXSQRT, set_fpcc, retaddr); } @@ -276,13 +276,13 @@ static void float_invalid_op_vxsqrt(CPUPPCState *env, bool set_fpcc, static void float_invalid_op_vxvc(CPUPPCState *env, bool set_fpcc, uintptr_t retaddr) { - env->fpscr |= 1 << FPSCR_VXVC; + env->fpscr |= FP_VXVC; if (set_fpcc) { - env->fpscr &= ~(0xF << FPSCR_FPCC); - env->fpscr |= 0x11 << FPSCR_FPCC; + env->fpscr &= ~FP_FPCC; + env->fpscr |= (FP_C | FP_FU); } /* Update the floating-point invalid operation summary */ - env->fpscr |= 1 << FPSCR_VX; + env->fpscr |= FP_VX; /* Update the floating-point exception summary */ env->fpscr |= FP_FX; /* We must update the target FPR before raising the exception */ @@ -292,7 +292,7 @@ static void float_invalid_op_vxvc(CPUPPCState *env, bool set_fpcc, cs->exception_index = POWERPC_EXCP_PROGRAM; env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC; /* Update the floating-point enabled exception summary */ - env->fpscr |= 1 << FPSCR_FEX; + env->fpscr |= FP_FEX; /* Exception is differed */ } } @@ -301,12 +301,12 @@ static void float_invalid_op_vxvc(CPUPPCState *env, bool set_fpcc, static void float_invalid_op_vxcvi(CPUPPCState *env, bool set_fpcc, uintptr_t retaddr) { - env->fpscr |= 1 << FPSCR_VXCVI; - env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); + env->fpscr |= FP_VXCVI; + env->fpscr &= ~(FP_FR | FP_FI); if (fpscr_ve == 0) { if (set_fpcc) { - env->fpscr &= ~(0xF << FPSCR_FPCC); - env->fpscr |= 0x11 << FPSCR_FPCC; + env->fpscr &= ~FP_FPCC; + env->fpscr |= (FP_C | FP_FU); } } finish_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, retaddr); @@ -314,13 +314,13 @@ static void float_invalid_op_vxcvi(CPUPPCState *env, bool set_fpcc, static inline void float_zero_divide_excp(CPUPPCState *env, uintptr_t raddr) { - env->fpscr |= 1 << FPSCR_ZX; - env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); + env->fpscr |= FP_ZX; + env->fpscr &= ~(FP_FR | FP_FI); /* Update the floating-point exception summary */ env->fpscr |= FP_FX; if (fpscr_ze != 0) { /* Update the floating-point enabled exception summary */ - env->fpscr |= 1 << FPSCR_FEX; + env->fpscr |= FP_FEX; if (fp_exceptions_enabled(env)) { raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX, @@ -333,19 +333,19 @@ static inline void float_overflow_excp(CPUPPCState *env) { CPUState *cs = env_cpu(env); - env->fpscr |= 1 << FPSCR_OX; + env->fpscr |= FP_OX; /* Update the floating-point exception summary */ env->fpscr |= FP_FX; if (fpscr_oe != 0) { /* XXX: should adjust the result */ /* Update the floating-point enabled exception summary */ - env->fpscr |= 1 << FPSCR_FEX; + env->fpscr |= FP_FEX; /* We must update the target FPR before raising the exception */ cs->exception_index = POWERPC_EXCP_PROGRAM; env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX; } else { - env->fpscr |= 1 << FPSCR_XX; - env->fpscr |= 1 << FPSCR_FI; + env->fpscr |= FP_XX; + env->fpscr |= FP_FI; } } @@ -353,13 +353,13 @@ static inline void float_underflow_excp(CPUPPCState *env) { CPUState *cs = env_cpu(env); - env->fpscr |= 1 << FPSCR_UX; + env->fpscr |= FP_UX; /* Update the floating-point exception summary */ env->fpscr |= FP_FX; if (fpscr_ue != 0) { /* XXX: should adjust the result */ /* Update the floating-point enabled exception summary */ - env->fpscr |= 1 << FPSCR_FEX; + env->fpscr |= FP_FEX; /* We must update the target FPR before raising the exception */ cs->exception_index = POWERPC_EXCP_PROGRAM; env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX; @@ -370,13 +370,13 @@ static inline void float_inexact_excp(CPUPPCState *env) { CPUState *cs = env_cpu(env); - env->fpscr |= 1 << FPSCR_FI; - env->fpscr |= 1 << FPSCR_XX; + env->fpscr |= FP_FI; + env->fpscr |= FP_XX; /* Update the floating-point exception summary */ env->fpscr |= FP_FX; if (fpscr_xe != 0) { /* Update the floating-point enabled exception summary */ - env->fpscr |= 1 << FPSCR_FEX; + env->fpscr |= FP_FEX; /* We must update the target FPR before raising the exception */ cs->exception_index = POWERPC_EXCP_PROGRAM; env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX; @@ -433,7 +433,7 @@ void helper_fpscr_clrbit(CPUPPCState *env, uint32_t bit) case FPSCR_VXCVI: if (!fpscr_ix) { /* Set VX bit to zero */ - env->fpscr &= ~(1 << FPSCR_VX); + env->fpscr &= ~FP_VX; } break; case FPSCR_OX: @@ -447,7 +447,7 @@ void helper_fpscr_clrbit(CPUPPCState *env, uint32_t bit) case FPSCR_XE: if (!fpscr_eex) { /* Set the FEX bit */ - env->fpscr &= ~(1 << FPSCR_FEX); + env->fpscr &= ~FP_FEX; } break; default: @@ -504,7 +504,7 @@ void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit) case FPSCR_VXSOFT: case FPSCR_VXSQRT: case FPSCR_VXCVI: - env->fpscr |= 1 << FPSCR_VX; + env->fpscr |= FP_VX; env->fpscr |= FP_FX; if (fpscr_ve != 0) { goto raise_ve; @@ -580,7 +580,7 @@ void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit) break; raise_excp: /* Update the floating-point enabled exception summary */ - env->fpscr |= 1 << FPSCR_FEX; + env->fpscr |= FP_FEX; /* We have to update Rc1 before raising the exception */ cs->exception_index = POWERPC_EXCP_PROGRAM; break; @@ -596,8 +596,8 @@ void helper_store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask) prev = env->fpscr; new = (target_ulong)arg; - new &= ~0x60000000LL; - new |= prev & 0x60000000LL; + new &= ~(FP_FEX | FP_VX); + new |= prev & (FP_FEX | FP_VX); for (i = 0; i < sizeof(target_ulong) * 2; i++) { if (mask & (1 << i)) { env->fpscr &= ~(0xFLL << (4 * i)); @@ -606,17 +606,17 @@ void helper_store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask) } /* Update VX and FEX */ if (fpscr_ix != 0) { - env->fpscr |= 1 << FPSCR_VX; + env->fpscr |= FP_VX; } else { - env->fpscr &= ~(1 << FPSCR_VX); + env->fpscr &= ~FP_VX; } if ((fpscr_ex & fpscr_eex) != 0) { - env->fpscr |= 1 << FPSCR_FEX; + env->fpscr |= FP_FEX; cs->exception_index = POWERPC_EXCP_PROGRAM; /* XXX: we should compute it properly */ env->error_code = POWERPC_EXCP_FP; } else { - env->fpscr &= ~(1 << FPSCR_FEX); + env->fpscr &= ~FP_FEX; } fpscr_set_rounding_mode(env); } @@ -639,7 +639,7 @@ static void do_float_check_status(CPUPPCState *env, uintptr_t raddr) if (status & float_flag_inexact) { float_inexact_excp(env); } else { - env->fpscr &= ~(1 << FPSCR_FI); /* clear the FPSCR[FI] bit */ + env->fpscr &= ~FP_FI; /* clear the FPSCR[FI] bit */ } if (cs->exception_index == POWERPC_EXCP_PROGRAM && @@ -1138,8 +1138,8 @@ void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2, ret = 0x02UL; } - env->fpscr &= ~(0x0F << FPSCR_FPRF); - env->fpscr |= ret << FPSCR_FPRF; + env->fpscr &= ~FP_FPCC; + env->fpscr |= ret << FPSCR_FPCC; env->crf[crfD] = ret; if (unlikely(ret == 0x01UL && (float64_is_signaling_nan(farg1.d, &env->fp_status) || @@ -1169,9 +1169,9 @@ void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2, ret = 0x02UL; } - env->fpscr &= ~(0x0F << FPSCR_FPRF); - env->fpscr |= ret << FPSCR_FPRF; - env->crf[crfD] = ret; + env->fpscr &= ~FP_FPCC; + env->fpscr |= ret << FPSCR_FPCC; + env->crf[crfD] = (uint32_t) ret; if (unlikely(ret == 0x01UL)) { float_invalid_op_vxvc(env, 1, GETPC()); if (float64_is_signaling_nan(farg1.d, &env->fp_status) || @@ -2431,8 +2431,8 @@ void helper_xscmpexpdp(CPUPPCState *env, uint32_t opcode, } } - env->fpscr &= ~(0x0F << FPSCR_FPRF); - env->fpscr |= cc << FPSCR_FPRF; + env->fpscr &= ~FP_FPCC; + env->fpscr |= cc << FPSCR_FPCC; env->crf[BF(opcode)] = cc; do_float_check_status(env, GETPC()); @@ -2460,8 +2460,8 @@ void helper_xscmpexpqp(CPUPPCState *env, uint32_t opcode, } } - env->fpscr &= ~(0x0F << FPSCR_FPRF); - env->fpscr |= cc << FPSCR_FPRF; + env->fpscr &= ~FP_FPCC; + env->fpscr |= cc << FPSCR_FPCC; env->crf[BF(opcode)] = cc; do_float_check_status(env, GETPC()); @@ -2505,8 +2505,8 @@ void helper_##op(CPUPPCState *env, uint32_t opcode, \ cc |= CRF_EQ; \ } \ \ - env->fpscr &= ~(0x0F << FPSCR_FPRF); \ - env->fpscr |= cc << FPSCR_FPRF; \ + env->fpscr &= ~FP_FPCC; \ + env->fpscr |= cc << FPSCR_FPCC; \ env->crf[BF(opcode)] = cc; \ \ do_float_check_status(env, GETPC()); \ @@ -2553,8 +2553,8 @@ void helper_##op(CPUPPCState *env, uint32_t opcode, \ cc |= CRF_EQ; \ } \ \ - env->fpscr &= ~(0x0F << FPSCR_FPRF); \ - env->fpscr |= cc << FPSCR_FPRF; \ + env->fpscr &= ~FP_FPCC; \ + env->fpscr |= cc << FPSCR_FPCC; \ env->crf[BF(opcode)] = cc; \ \ do_float_check_status(env, GETPC()); \ @@ -3242,8 +3242,8 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ \ if (scrf) { \ cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT; \ - env->fpscr &= ~(0x0F << FPSCR_FPRF); \ - env->fpscr |= cc << FPSCR_FPRF; \ + env->fpscr &= ~FP_FPCC; \ + env->fpscr |= cc << FPSCR_FPCC; \ env->crf[BF(opcode)] = cc; \ } else { \ t.tfld = match ? fld_max : 0; \ @@ -3286,8 +3286,8 @@ void helper_xststdcsp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xb) &env->fp_status), &env->fp_status); cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT | not_sp << CRF_SO_BIT; - env->fpscr &= ~(0x0F << FPSCR_FPRF); - env->fpscr |= cc << FPSCR_FPRF; + env->fpscr &= ~FP_FPCC; + env->fpscr |= cc << FPSCR_FPCC; env->crf[BF(opcode)] = cc; } diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 54ea9b9500..f843814b8a 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -686,7 +686,7 @@ DEF_HELPER_3(store_601_batu, void, env, i32, tl) #endif #define dh_alias_fprp ptr -#define dh_ctype_fprp uint64_t * +#define dh_ctype_fprp ppc_fprp_t * #define dh_is_signed_fprp dh_is_signed_ptr DEF_HELPER_4(dadd, void, env, fprp, fprp, fprp) diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index 46deb57a34..6d238b989d 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -2052,15 +2052,11 @@ void helper_vsubecuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) #define NATIONAL_PLUS 0x2B #define NATIONAL_NEG 0x2D -#if defined(HOST_WORDS_BIGENDIAN) #define BCD_DIG_BYTE(n) (15 - ((n) / 2)) -#else -#define BCD_DIG_BYTE(n) ((n) / 2) -#endif static int bcd_get_sgn(ppc_avr_t *bcd) { - switch (bcd->u8[BCD_DIG_BYTE(0)] & 0xF) { + switch (bcd->VsrB(BCD_DIG_BYTE(0)) & 0xF) { case BCD_PLUS_PREF_1: case BCD_PLUS_PREF_2: case BCD_PLUS_ALT_1: @@ -2095,9 +2091,9 @@ static uint8_t bcd_get_digit(ppc_avr_t *bcd, int n, int *invalid) { uint8_t result; if (n & 1) { - result = bcd->u8[BCD_DIG_BYTE(n)] >> 4; + result = bcd->VsrB(BCD_DIG_BYTE(n)) >> 4; } else { - result = bcd->u8[BCD_DIG_BYTE(n)] & 0xF; + result = bcd->VsrB(BCD_DIG_BYTE(n)) & 0xF; } if (unlikely(result > 9)) { @@ -2109,11 +2105,11 @@ static uint8_t bcd_get_digit(ppc_avr_t *bcd, int n, int *invalid) static void bcd_put_digit(ppc_avr_t *bcd, uint8_t digit, int n) { if (n & 1) { - bcd->u8[BCD_DIG_BYTE(n)] &= 0x0F; - bcd->u8[BCD_DIG_BYTE(n)] |= (digit << 4); + bcd->VsrB(BCD_DIG_BYTE(n)) &= 0x0F; + bcd->VsrB(BCD_DIG_BYTE(n)) |= (digit << 4); } else { - bcd->u8[BCD_DIG_BYTE(n)] &= 0xF0; - bcd->u8[BCD_DIG_BYTE(n)] |= digit; + bcd->VsrB(BCD_DIG_BYTE(n)) &= 0xF0; + bcd->VsrB(BCD_DIG_BYTE(n)) |= digit; } } @@ -2228,21 +2224,21 @@ uint32_t helper_bcdadd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps) if (!invalid) { if (sgna == sgnb) { - result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgna, ps); + result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(sgna, ps); bcd_add_mag(&result, a, b, &invalid, &overflow); cr = bcd_cmp_zero(&result); } else { int magnitude = bcd_cmp_mag(a, b); if (magnitude > 0) { - result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgna, ps); + result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(sgna, ps); bcd_sub_mag(&result, a, b, &invalid, &overflow); cr = (sgna > 0) ? CRF_GT : CRF_LT; } else if (magnitude < 0) { - result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgnb, ps); + result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(sgnb, ps); bcd_sub_mag(&result, b, a, &invalid, &overflow); cr = (sgnb > 0) ? CRF_GT : CRF_LT; } else { - result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(0, ps); + result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(0, ps); cr = CRF_EQ; } } @@ -2353,15 +2349,15 @@ uint32_t helper_bcdcfz(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps) int zone_lead = ps ? 0xF : 0x3; int digit = 0; ppc_avr_t ret = { .u64 = { 0, 0 } }; - int sgnb = b->u8[BCD_DIG_BYTE(0)] >> 4; + int sgnb = b->VsrB(BCD_DIG_BYTE(0)) >> 4; if (unlikely((sgnb < 0xA) && ps)) { invalid = 1; } for (i = 0; i < 16; i++) { - zone_digit = i ? b->u8[BCD_DIG_BYTE(i * 2)] >> 4 : zone_lead; - digit = b->u8[BCD_DIG_BYTE(i * 2)] & 0xF; + zone_digit = i ? b->VsrB(BCD_DIG_BYTE(i * 2)) >> 4 : zone_lead; + digit = b->VsrB(BCD_DIG_BYTE(i * 2)) & 0xF; if (unlikely(zone_digit != zone_lead || digit > 0x9)) { invalid = 1; break; @@ -2407,7 +2403,7 @@ uint32_t helper_bcdctz(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps) break; } - ret.u8[BCD_DIG_BYTE(i * 2)] = zone_lead + digit; + ret.VsrB(BCD_DIG_BYTE(i * 2)) = zone_lead + digit; } if (ps) { @@ -2519,7 +2515,7 @@ uint32_t helper_bcdcpsgn(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps) } *r = *a; - bcd_put_digit(r, b->u8[BCD_DIG_BYTE(0)] & 0xF, 0); + bcd_put_digit(r, b->VsrB(BCD_DIG_BYTE(0)) & 0xF, 0); for (i = 1; i < 32; i++) { bcd_get_digit(a, i, &invalid); @@ -2549,11 +2545,7 @@ uint32_t helper_bcdsetsgn(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps) uint32_t helper_bcds(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps) { int cr; -#if defined(HOST_WORDS_BIGENDIAN) - int i = a->s8[7]; -#else - int i = a->s8[8]; -#endif + int i = a->VsrSB(7); bool ox_flag = false; int sgnb = bcd_get_sgn(b); ppc_avr_t ret = *b; @@ -2602,11 +2594,7 @@ uint32_t helper_bcdus(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps) } } -#if defined(HOST_WORDS_BIGENDIAN) - i = a->s8[7]; -#else - i = a->s8[8]; -#endif + i = a->VsrSB(7); if (i >= 32) { ox_flag = true; ret.VsrD(1) = ret.VsrD(0) = 0; @@ -2637,13 +2625,11 @@ uint32_t helper_bcdsr(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps) ppc_avr_t ret = *b; ret.VsrD(1) &= ~0xf; -#if defined(HOST_WORDS_BIGENDIAN) - int i = a->s8[7]; - ppc_avr_t bcd_one = { .u64 = { 0, 0x10 } }; -#else - int i = a->s8[8]; - ppc_avr_t bcd_one = { .u64 = { 0x10, 0 } }; -#endif + int i = a->VsrSB(7); + ppc_avr_t bcd_one; + + bcd_one.VsrD(0) = 0; + bcd_one.VsrD(1) = 0x10; if (bcd_is_valid(b) == false) { return CRF_SO; @@ -2679,11 +2665,7 @@ uint32_t helper_bcdtrunc(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps) { uint64_t mask; uint32_t ox_flag = 0; -#if defined(HOST_WORDS_BIGENDIAN) - int i = a->s16[3] + 1; -#else - int i = a->s16[4] + 1; -#endif + int i = a->VsrSH(3) + 1; ppc_avr_t ret = *b; if (bcd_is_valid(b) == false) { @@ -2728,11 +2710,7 @@ uint32_t helper_bcdutrunc(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps) } } -#if defined(HOST_WORDS_BIGENDIAN) - i = a->s16[3]; -#else - i = a->s16[4]; -#endif + i = a->VsrSH(3); if (i > 16 && i < 33) { mask = (uint64_t)-1 >> (128 - i * 4); if (ret.VsrD(0) & ~mask) { diff --git a/target/ppc/internal.h b/target/ppc/internal.h index d3d327e548..15d655b356 100644 --- a/target/ppc/internal.h +++ b/target/ppc/internal.h @@ -157,6 +157,9 @@ EXTRACT_HELPER(FPL, 25, 1); EXTRACT_HELPER(FPFLM, 17, 8); EXTRACT_HELPER(FPW, 16, 1); +/* mffscrni */ +EXTRACT_HELPER(RM, 11, 2); + /* addpcis */ EXTRACT_HELPER_SPLIT_3(DX, 10, 6, 6, 5, 16, 1, 1, 0, 0) #if defined(TARGET_PPC64) diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 8c5b1f25cc..820724cc7d 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -993,6 +993,10 @@ int kvm_arch_put_registers(CPUState *cs, int level) } kvm_set_one_reg(cs, KVM_REG_PPC_TB_OFFSET, &env->tb_env->tb_offset); + + if (level > KVM_PUT_RUNTIME_STATE) { + kvm_put_one_spr(cs, KVM_REG_PPC_DPDES, SPR_DPDES); + } #endif /* TARGET_PPC64 */ } @@ -1297,6 +1301,7 @@ int kvm_arch_get_registers(CPUState *cs) } kvm_get_one_reg(cs, KVM_REG_PPC_TB_OFFSET, &env->tb_env->tb_offset); + kvm_get_one_spr(cs, KVM_REG_PPC_DPDES, SPR_DPDES); #endif } diff --git a/target/ppc/translate/fp-impl.inc.c b/target/ppc/translate/fp-impl.inc.c index 7cd9d8db05..d8e27bf4d5 100644 --- a/target/ppc/translate/fp-impl.inc.c +++ b/target/ppc/translate/fp-impl.inc.c @@ -634,11 +634,108 @@ static void gen_mffsl(DisasContext *ctx) gen_reset_fpstatus(); tcg_gen_extu_tl_i64(t0, cpu_fpscr); /* Mask everything except mode, status, and enables. */ - tcg_gen_andi_i64(t0, t0, FP_MODE | FP_STATUS | FP_ENABLES); + tcg_gen_andi_i64(t0, t0, FP_DRN | FP_STATUS | FP_ENABLES | FP_RN); set_fpr(rD(ctx->opcode), t0); tcg_temp_free_i64(t0); } +/* mffsce */ +static void gen_mffsce(DisasContext *ctx) +{ + TCGv_i64 t0; + TCGv_i32 mask; + + if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) { + return gen_mffs(ctx); + } + + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + + t0 = tcg_temp_new_i64(); + + gen_reset_fpstatus(); + tcg_gen_extu_tl_i64(t0, cpu_fpscr); + set_fpr(rD(ctx->opcode), t0); + + /* Clear exception enable bits in the FPSCR. */ + tcg_gen_andi_i64(t0, t0, ~FP_ENABLES); + mask = tcg_const_i32(0x0003); + gen_helper_store_fpscr(cpu_env, t0, mask); + + tcg_temp_free_i32(mask); + tcg_temp_free_i64(t0); +} + +static void gen_helper_mffscrn(DisasContext *ctx, TCGv_i64 t1) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i32 mask = tcg_const_i32(0x0001); + + gen_reset_fpstatus(); + tcg_gen_extu_tl_i64(t0, cpu_fpscr); + tcg_gen_andi_i64(t0, t0, FP_DRN | FP_ENABLES | FP_RN); + set_fpr(rD(ctx->opcode), t0); + + /* Mask FPSCR value to clear RN. */ + tcg_gen_andi_i64(t0, t0, ~FP_RN); + + /* Merge RN into FPSCR value. */ + tcg_gen_or_i64(t0, t0, t1); + + gen_helper_store_fpscr(cpu_env, t0, mask); + + tcg_temp_free_i32(mask); + tcg_temp_free_i64(t0); +} + +/* mffscrn */ +static void gen_mffscrn(DisasContext *ctx) +{ + TCGv_i64 t1; + + if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) { + return gen_mffs(ctx); + } + + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + + t1 = tcg_temp_new_i64(); + get_fpr(t1, rB(ctx->opcode)); + /* Mask FRB to get just RN. */ + tcg_gen_andi_i64(t1, t1, FP_RN); + + gen_helper_mffscrn(ctx, t1); + + tcg_temp_free_i64(t1); +} + +/* mffscrni */ +static void gen_mffscrni(DisasContext *ctx) +{ + TCGv_i64 t1; + + if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) { + return gen_mffs(ctx); + } + + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + + t1 = tcg_const_i64((uint64_t)RM(ctx->opcode)); + + gen_helper_mffscrn(ctx, t1); + + tcg_temp_free_i64(t1); +} + /* mtfsb0 */ static void gen_mtfsb0(DisasContext *ctx) { diff --git a/target/ppc/translate/fp-ops.inc.c b/target/ppc/translate/fp-ops.inc.c index 88ebc2526c..88fab65628 100644 --- a/target/ppc/translate/fp-ops.inc.c +++ b/target/ppc/translate/fp-ops.inc.c @@ -105,8 +105,14 @@ GEN_HANDLER_E(fmrgew, 0x3F, 0x06, 0x1E, 0x00000001, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(fmrgow, 0x3F, 0x06, 0x1A, 0x00000001, PPC_NONE, PPC2_VSX207), GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT), GEN_HANDLER_E_2(mffs, 0x3F, 0x07, 0x12, 0x00, 0x00000000, PPC_FLOAT, PPC_NONE), +GEN_HANDLER_E_2(mffsce, 0x3F, 0x07, 0x12, 0x01, 0x00000000, PPC_FLOAT, + PPC2_ISA300), GEN_HANDLER_E_2(mffsl, 0x3F, 0x07, 0x12, 0x18, 0x00000000, PPC_FLOAT, PPC2_ISA300), +GEN_HANDLER_E_2(mffscrn, 0x3F, 0x07, 0x12, 0x16, 0x00000000, PPC_FLOAT, + PPC_NONE), +GEN_HANDLER_E_2(mffscrni, 0x3F, 0x07, 0x12, 0x17, 0x00000000, PPC_FLOAT, + PPC_NONE), GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT), GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT), GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x00000000, PPC_FLOAT), diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c index 0fb11c7ac6..ba726dec4d 100644 --- a/target/ppc/translate_init.inc.c +++ b/target/ppc/translate_init.inc.c @@ -8200,11 +8200,10 @@ static void gen_spr_power8_dpdes(CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) /* Directed Privileged Door-bell Exception State, used for IPI */ - spr_register_kvm_hv(env, SPR_DPDES, "DPDES", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - KVM_REG_PPC_DPDES, 0x00000000); + spr_register(env, SPR_DPDES, "DPDES", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); #endif } diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index 97a662ad0e..c24c869e77 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -28,6 +28,7 @@ #include "cpu.h" #include "internal.h" #include "kvm_s390x.h" +#include "sysemu/kvm_int.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/timer.h" @@ -122,6 +123,14 @@ */ #define VCPU_IRQ_BUF_SIZE(max_cpus) (sizeof(struct kvm_s390_irq) * \ (max_cpus + NR_LOCAL_IRQS)) +/* + * KVM does only support memory slots up to KVM_MEM_MAX_NR_PAGES pages + * as the dirty bitmap must be managed by bitops that take an int as + * position indicator. This would end at an unaligned address + * (0x7fffff00000). As future variants might provide larger pages + * and to make all addresses properly aligned, let us split at 4TB. + */ +#define KVM_SLOT_MAX_BYTES (4UL * TiB) static CPUWatchpoint hw_watchpoint; /* @@ -355,6 +364,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) */ /* kvm_vm_enable_cap(s, KVM_CAP_S390_AIS, 0); */ + kvm_set_max_memslot_size(KVM_SLOT_MAX_BYTES); return 0; } diff --git a/tests/Makefile.include b/tests/Makefile.include index 479664f899..3543451ed3 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -182,9 +182,7 @@ check-qtest-i386-$(CONFIG_PVPANIC) += tests/pvpanic-test$(EXESUF) check-qtest-i386-$(CONFIG_I82801B11) += tests/i82801b11-test$(EXESUF) check-qtest-i386-$(CONFIG_IOH3420) += tests/ioh3420-test$(EXESUF) check-qtest-i386-$(CONFIG_USB_UHCI) += tests/usb-hcd-uhci-test$(EXESUF) -ifeq ($(CONFIG_USB_ECHI)$(CONFIG_USB_UHCI),yy) -check-qtest-i386-y += tests/usb-hcd-ehci-test$(EXESUF) -endif +check-qtest-i386-$(call land,$(CONFIG_USB_EHCI),$(CONFIG_USB_UHCI)) += tests/usb-hcd-ehci-test$(EXESUF) check-qtest-i386-$(CONFIG_USB_XHCI_NEC) += tests/usb-hcd-xhci-test$(EXESUF) check-qtest-i386-y += tests/cpu-plug-test$(EXESUF) check-qtest-i386-y += tests/q35-test$(EXESUF) @@ -294,6 +292,7 @@ check-qtest-generic-y += tests/test-hmp$(EXESUF) qapi-schema += alternate-any.json qapi-schema += alternate-array.json qapi-schema += alternate-base.json +qapi-schema += alternate-branch-if-invalid.json qapi-schema += alternate-clash.json qapi-schema += alternate-conflict-dict.json qapi-schema += alternate-conflict-enum-bool.json @@ -311,7 +310,6 @@ qapi-schema += args-array-empty.json qapi-schema += args-array-unknown.json qapi-schema += args-bad-boxed.json qapi-schema += args-boxed-anon.json -qapi-schema += args-boxed-empty.json qapi-schema += args-boxed-string.json qapi-schema += args-int.json qapi-schema += args-invalid.json @@ -360,7 +358,6 @@ qapi-schema += doc-missing-expr.json qapi-schema += doc-missing-space.json qapi-schema += doc-missing.json qapi-schema += doc-no-symbol.json -qapi-schema += double-data.json qapi-schema += double-type.json qapi-schema += duplicate-key.json qapi-schema += empty.json @@ -374,15 +371,13 @@ qapi-schema += enum-int-member.json qapi-schema += enum-member-case.json qapi-schema += enum-missing-data.json qapi-schema += enum-wrong-data.json -qapi-schema += escape-outside-string.json -qapi-schema += escape-too-big.json -qapi-schema += escape-too-short.json qapi-schema += event-boxed-empty.json qapi-schema += event-case.json qapi-schema += event-member-invalid-dict.json qapi-schema += event-nest-struct.json qapi-schema += features-bad-type.json qapi-schema += features-duplicate-name.json +qapi-schema += features-if-invalid.json qapi-schema += features-missing-name.json qapi-schema += features-name-bad-type.json qapi-schema += features-no-list.json @@ -393,6 +388,7 @@ qapi-schema += flat-union-bad-discriminator.json qapi-schema += flat-union-base-any.json qapi-schema += flat-union-base-union.json qapi-schema += flat-union-clash-member.json +qapi-schema += flat-union-discriminator-bad-name.json qapi-schema += flat-union-empty.json qapi-schema += flat-union-inline.json qapi-schema += flat-union-inline-invalid-dict.json @@ -404,11 +400,11 @@ qapi-schema += flat-union-no-base.json qapi-schema += flat-union-optional-discriminator.json qapi-schema += flat-union-string-discriminator.json qapi-schema += funny-char.json +qapi-schema += funny-word.json qapi-schema += ident-with-escape.json qapi-schema += include-before-err.json qapi-schema += include-cycle.json qapi-schema += include-extra-junk.json -qapi-schema += include-format-err.json qapi-schema += include-nested-err.json qapi-schema += include-no-file.json qapi-schema += include-non-file.json @@ -431,6 +427,7 @@ qapi-schema += pragma-doc-required-crap.json qapi-schema += pragma-extra-junk.json qapi-schema += pragma-name-case-whitelist-crap.json qapi-schema += pragma-non-dict.json +qapi-schema += pragma-unknown.json qapi-schema += pragma-returns-whitelist-crap.json qapi-schema += qapi-schema-test.json qapi-schema += quoted-structural-chars.json @@ -451,9 +448,12 @@ qapi-schema += returns-array-bad.json qapi-schema += returns-dict.json qapi-schema += returns-unknown.json qapi-schema += returns-whitelist.json +qapi-schema += string-code-point-31.json +qapi-schema += string-code-point-127.json qapi-schema += struct-base-clash-deep.json qapi-schema += struct-base-clash.json qapi-schema += struct-data-invalid.json +qapi-schema += struct-member-if-invalid.json qapi-schema += struct-member-invalid-dict.json qapi-schema += struct-member-invalid.json qapi-schema += trailing-comma-list.json @@ -462,10 +462,10 @@ qapi-schema += type-bypass-bad-gen.json qapi-schema += unclosed-list.json qapi-schema += unclosed-object.json qapi-schema += unclosed-string.json -qapi-schema += unicode-str.json qapi-schema += union-base-empty.json qapi-schema += union-base-no-discriminator.json qapi-schema += union-branch-case.json +qapi-schema += union-branch-if-invalid.json qapi-schema += union-branch-invalid-dict.json qapi-schema += union-clash-branches.json qapi-schema += union-empty.json diff --git a/tests/cdrom-test.c b/tests/cdrom-test.c index 05611da648..34e9974634 100644 --- a/tests/cdrom-test.c +++ b/tests/cdrom-test.c @@ -120,7 +120,7 @@ static void test_cdboot(gconstpointer data) { QTestState *qts; - qts = qtest_initf("-accel kvm:tcg -no-shutdown %s%s", (const char *)data, + qts = qtest_initf("-M accel=kvm:tcg -no-shutdown %s%s", (const char *)data, isoimage); boot_sector_test(qts); qtest_quit(qts); diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index 50a400b573..89c56a3a88 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -4,11 +4,10 @@ DOCKER_SUFFIX := .docker DOCKER_FILES_DIR := $(SRC_PATH)/tests/docker/dockerfiles -DOCKER_DEPRECATED_IMAGES := debian # we don't run tests on intermediate images (used as base by another image) -DOCKER_PARTIAL_IMAGES := debian debian8 debian9 debian10 debian-sid -DEBIAN_PARTIAL_IMAGES += debian8-mxe debian-9-mxe debian-ports debian-bootstrap -DOCKER_IMAGES := $(filter-out $(DOCKER_DEPRECATED_IMAGES),$(sort $(notdir $(basename $(wildcard $(DOCKER_FILES_DIR)/*.docker))))) +DOCKER_PARTIAL_IMAGES := debian9 debian10 +DOCKER_PARTIAL_IMAGES += debian9-mxe debian-bootstrap +DOCKER_IMAGES := $(sort $(notdir $(basename $(wildcard $(DOCKER_FILES_DIR)/*.docker)))) DOCKER_TARGETS := $(patsubst %,docker-image-%,$(DOCKER_IMAGES)) # Use a global constant ccache directory to speed up repetitive builds DOCKER_CCACHE_DIR := $$HOME/.cache/qemu-docker-ccache @@ -148,17 +147,8 @@ DOCKER_PARTIAL_IMAGES += fedora-i386-cross fedora-cris-cross # work around issues with poorly working multi-arch systems and broken # packages. -# Jessie is the last supported release for powerpc, but multi-arch is -# broken so we need a qemu-linux-user for this target -docker-binfmt-image-debian-powerpc-user: DEB_ARCH = powerpc -docker-binfmt-image-debian-powerpc-user: DEB_TYPE = jessie -docker-binfmt-image-debian-powerpc-user: DEB_URL = http://snapshot.debian.org/archive/debian/20180615T211437Z -docker-binfmt-image-debian-powerpc-user: EXECUTABLE = ${BUILD_DIR}/ppc-linux-user/qemu-ppc -docker-image-debian-powerpc-user-cross: docker-binfmt-image-debian-powerpc-user -DOCKER_USER_IMAGES += debian-powerpc-user - # Expand all the pre-requistes for each docker image and test combination -$(foreach i,$(filter-out $(DOCKER_PARTIAL_IMAGES),$(DOCKER_IMAGES) $(DOCKER_DEPRECATED_IMAGES)), \ +$(foreach i,$(filter-out $(DOCKER_PARTIAL_IMAGES),$(DOCKER_IMAGES)), \ $(foreach t,$(DOCKER_TESTS) $(DOCKER_TOOLS), \ $(eval .PHONY: docker-$t@$i) \ $(eval docker-$t@$i: docker-image-$i docker-run-$t@$i) \ diff --git a/tests/docker/docker.py b/tests/docker/docker.py index 29613afd48..31d8adf836 100755 --- a/tests/docker/docker.py +++ b/tests/docker/docker.py @@ -215,7 +215,7 @@ class Docker(object): """ Running Docker commands """ def __init__(self): self._command = _guess_engine_command() - self._instances = [] + self._instance = None atexit.register(self._kill_instances) signal.signal(signal.SIGTERM, self._kill_instances) signal.signal(signal.SIGHUP, self._kill_instances) @@ -234,21 +234,19 @@ class Docker(object): cmd = ["ps", "-q"] if not only_active: cmd.append("-a") + + filter = "--filter=label=com.qemu.instance.uuid" + if only_known: + if self._instance: + filter += "=%s" % (self._instance) + else: + # no point trying to kill, we finished + return + + print("filter=%s" % (filter)) + cmd.append(filter) for i in self._output(cmd).split(): - resp = self._output(["inspect", i]) - labels = json.loads(resp)[0]["Config"]["Labels"] - active = json.loads(resp)[0]["State"]["Running"] - if not labels: - continue - instance_uuid = labels.get("com.qemu.instance.uuid", None) - if not instance_uuid: - continue - if only_known and instance_uuid not in self._instances: - continue - print("Terminating", i) - if active: - self._do(["kill", i]) - self._do(["rm", i]) + self._do(["rm", "-f", i]) def clean(self): self._do_kill_instances(False, False) @@ -325,22 +323,22 @@ class Docker(object): return checksum == _text_checksum(_dockerfile_preprocess(dockerfile)) def run(self, cmd, keep, quiet, as_user=False): - label = uuid.uuid1().hex + label = uuid.uuid4().hex if not keep: - self._instances.append(label) + self._instance = label if as_user: uid = os.getuid() cmd = [ "-u", str(uid) ] + cmd # podman requires a bit more fiddling if self._command[0] == "podman": - argv.insert(0, '--userns=keep-id') + cmd.insert(0, '--userns=keep-id') ret = self._do_check(["run", "--label", "com.qemu.instance.uuid=" + label] + cmd, quiet=quiet) if not keep: - self._instances.remove(label) + self._instance = None return ret def command(self, cmd, argv, quiet): diff --git a/tests/docker/dockerfiles/centos7.docker b/tests/docker/dockerfiles/centos7.docker index e0b9d7dbe9..953637065c 100644 --- a/tests/docker/dockerfiles/centos7.docker +++ b/tests/docker/dockerfiles/centos7.docker @@ -25,6 +25,7 @@ ENV PACKAGES \ nettle-devel \ perl-Test-Harness \ pixman-devel \ + python3 \ SDL-devel \ spice-glib-devel \ spice-server-devel \ @@ -34,4 +35,3 @@ ENV PACKAGES \ zlib-devel RUN yum install -y $PACKAGES RUN rpm -q $PACKAGES | sort > /packages.txt - diff --git a/tests/docker/dockerfiles/debian-ports.docker b/tests/docker/dockerfiles/debian-ports.docker deleted file mode 100644 index 61bc3f2993..0000000000 --- a/tests/docker/dockerfiles/debian-ports.docker +++ /dev/null @@ -1,36 +0,0 @@ -# -# Docker multiarch cross-compiler target -# -# This docker target is builds on Debian Ports cross compiler targets -# to build distro with a selection of cross compilers for building test binaries. -# -# On its own you can't build much but the docker-foo-cross targets -# build on top of the base debian image. -# -FROM debian:unstable - -MAINTAINER Philippe Mathieu-DaudĂ© <f4bug@amsat.org> - -RUN echo "deb [arch=amd64] http://deb.debian.org/debian unstable main" > /etc/apt/sources.list - -# Duplicate deb line as deb-src -RUN cat /etc/apt/sources.list | sed -ne "s/^deb\ \(\[.*\]\ \)\?\(.*\)/deb-src \2/p" >> /etc/apt/sources.list - -# Setup some basic tools we need -RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt-get install -y --no-install-recommends \ - bison \ - build-essential \ - ca-certificates \ - clang \ - debian-ports-archive-keyring \ - flex \ - gettext \ - git \ - pkg-config \ - psmisc \ - python \ - texinfo \ - $(apt-get -s build-dep qemu | egrep ^Inst | fgrep '[all]' | cut -d\ -f2) diff --git a/tests/docker/dockerfiles/debian-powerpc-user-cross.docker b/tests/docker/dockerfiles/debian-powerpc-user-cross.docker deleted file mode 100644 index 83749b0abb..0000000000 --- a/tests/docker/dockerfiles/debian-powerpc-user-cross.docker +++ /dev/null @@ -1,21 +0,0 @@ -# -# Docker powerpc cross-compiler target for QEMU -# -# We can't use current Debian stable cross-compilers to build powerpc -# as it has been dropped as a release architecture. Using Debian Sid -# is just far too sketchy a build environment. This leaves us the -# final option of using linux-user. This image is based of the -# debootstrapped qemu:debian-powerpc-user but doesn't need any extra -# magic once it is setup. -# -# It can be used to build old versions of QEMU, current versions need -# newer dependencies than Jessie provides. -# -FROM qemu:debian-powerpc-user - -RUN echo man-db man-db/auto-update boolean false | debconf-set-selections -RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get build-dep -yy qemu - -ENV QEMU_CONFIGURE_OPTS --disable-werror -ENV DEF_TARGET_LIST powerpc-softmmu,arm-linux-user,aarch64-linux-user diff --git a/tests/docker/dockerfiles/debian-sid.docker b/tests/docker/dockerfiles/debian-sid.docker deleted file mode 100644 index 2a1bcc33b2..0000000000 --- a/tests/docker/dockerfiles/debian-sid.docker +++ /dev/null @@ -1,35 +0,0 @@ -# -# Debian Sid Base -# -# Currently we can build all our guests with cross-compilers in the -# latest Debian release (Buster). However new compilers will first -# arrive in Sid. However Sid is a rolling distro which may be broken -# at any particular time. To try and mitigate this we use Debian's -# snapshot archive which provides a "stable" view of what state Sid -# was in. -# - -# This must be earlier than the snapshot date we are aiming for -FROM debian:sid-20190812-slim - - # Use a snapshot known to work (see http://snapshot.debian.org/#Usage) -ENV DEBIAN_SNAPSHOT_DATE "20190820" -RUN sed -i "s%^deb \(https\?://\)deb.debian.org/debian/\? \(.*\)%deb [check-valid-until=no] \1snapshot.debian.org/archive/debian/${DEBIAN_SNAPSHOT_DATE} \2%" /etc/apt/sources.list - -# Duplicate deb line as deb-src -RUN cat /etc/apt/sources.list | sed "s/^deb\ /deb-src /" >> /etc/apt/sources.list - -# Install common build utilities -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt install -y --no-install-recommends \ - bison \ - build-essential \ - ca-certificates \ - flex \ - git \ - pkg-config \ - psmisc \ - python \ - texinfo || { echo "Failed to build - see debian-sid.docker notes"; exit 1; } diff --git a/tests/docker/dockerfiles/debian-xtensa-cross.docker b/tests/docker/dockerfiles/debian-xtensa-cross.docker index b9c2e2e531..e6f93f65ee 100644 --- a/tests/docker/dockerfiles/debian-xtensa-cross.docker +++ b/tests/docker/dockerfiles/debian-xtensa-cross.docker @@ -18,7 +18,7 @@ RUN apt-get update && \ flex \ gettext \ git \ - python-minimal + python3-minimal ENV CPU_LIST csp dc232b dc233c ENV TOOLCHAIN_RELEASE 2018.02 diff --git a/tests/docker/dockerfiles/debian10.docker b/tests/docker/dockerfiles/debian10.docker index 30a78813f2..dad498b52e 100644 --- a/tests/docker/dockerfiles/debian10.docker +++ b/tests/docker/dockerfiles/debian10.docker @@ -26,7 +26,7 @@ RUN apt update && \ git \ pkg-config \ psmisc \ - python \ + python3 \ python3-sphinx \ texinfo \ $(apt-get -s build-dep qemu | egrep ^Inst | fgrep '[all]' | cut -d\ -f2) diff --git a/tests/docker/dockerfiles/debian8.docker b/tests/docker/dockerfiles/debian8.docker deleted file mode 100644 index 1212a85c35..0000000000 --- a/tests/docker/dockerfiles/debian8.docker +++ /dev/null @@ -1,34 +0,0 @@ -# -# Docker multiarch cross-compiler target -# -# This docker target is builds on Debian and Emdebian's cross compiler targets -# to build distro with a selection of cross compilers for building test binaries. -# -# On its own you can't build much but the docker-foo-cross targets -# build on top of the base debian image. -# -FROM debian:jessie-slim - -MAINTAINER Philippe Mathieu-DaudĂ© <f4bug@amsat.org> - -# Duplicate deb line as deb-src -RUN cat /etc/apt/sources.list | sed "s/^deb\ /deb-src /" >> /etc/apt/sources.list - -# Setup some basic tools we need -RUN apt update && \ - DEBIAN_FRONTEND=noninteractive apt-get install -yy eatmydata && \ - DEBIAN_FRONTEND=noninteractive eatmydata \ - apt-get install -y --no-install-recommends \ - bison \ - binutils-multiarch \ - build-essential \ - ca-certificates \ - clang \ - curl \ - flex \ - gettext \ - git \ - gnupg \ - pkg-config \ - python-minimal - diff --git a/tests/docker/dockerfiles/debian9-mxe.docker b/tests/docker/dockerfiles/debian9-mxe.docker index 7431168dad..62ff1cecf2 100644 --- a/tests/docker/dockerfiles/debian9-mxe.docker +++ b/tests/docker/dockerfiles/debian9-mxe.docker @@ -16,7 +16,6 @@ RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C6BF758A33A3A276 && RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive eatmydata \ apt-get install -y --no-install-recommends \ - libpython2.7-stdlib \ $(apt-get -s install -y --no-install-recommends gw32.shared-mingw-w64 | egrep "^Inst mxe-x86-64-unknown-" | cut -d\ -f2) -ENV PATH $PATH:/usr/lib/mxe/usr/bin/ +ENV PATH $PATH:/usr/lib/mxe/usr/bin/ diff --git a/tests/docker/dockerfiles/debian9.docker b/tests/docker/dockerfiles/debian9.docker index b36f1d4ed8..8cbd742bb5 100644 --- a/tests/docker/dockerfiles/debian9.docker +++ b/tests/docker/dockerfiles/debian9.docker @@ -26,7 +26,7 @@ RUN apt update && \ git \ pkg-config \ psmisc \ - python \ + python3 \ python3-sphinx \ texinfo \ $(apt-get -s build-dep qemu | egrep ^Inst | fgrep '[all]' | cut -d\ -f2) diff --git a/tests/docker/dockerfiles/travis.docker b/tests/docker/dockerfiles/travis.docker index e72dc85ca7..ea14da29d9 100644 --- a/tests/docker/dockerfiles/travis.docker +++ b/tests/docker/dockerfiles/travis.docker @@ -5,7 +5,7 @@ ENV LC_ALL en_US.UTF-8 RUN sed -i "s/# deb-src/deb-src/" /etc/apt/sources.list RUN apt-get update RUN apt-get -y build-dep qemu -RUN apt-get -y install device-tree-compiler python2.7 python-yaml dh-autoreconf gdb strace lsof net-tools gcovr +RUN apt-get -y install device-tree-compiler python3 python3-yaml dh-autoreconf gdb strace lsof net-tools gcovr # Travis tools require PhantomJS / Neo4j / Maven accessible # in their PATH (QEMU build won't access them). ENV PATH /usr/local/phantomjs/bin:/usr/local/phantomjs:/usr/local/neo4j-3.2.7/bin:/usr/local/maven-3.5.2/bin:/usr/local/cmake-3.9.2/bin:/usr/local/clang-5.0.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin diff --git a/tests/docker/dockerfiles/ubuntu.docker b/tests/docker/dockerfiles/ubuntu.docker index a4f601395c..f486492224 100644 --- a/tests/docker/dockerfiles/ubuntu.docker +++ b/tests/docker/dockerfiles/ubuntu.docker @@ -60,7 +60,7 @@ ENV PACKAGES flex bison \ libvte-2.91-dev \ libxen-dev \ make \ - python-yaml \ + python3-yaml \ python3-sphinx \ sparse \ texinfo \ diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker index 883f9bcf31..3cc4f492c4 100644 --- a/tests/docker/dockerfiles/ubuntu1804.docker +++ b/tests/docker/dockerfiles/ubuntu1804.docker @@ -47,7 +47,7 @@ ENV PACKAGES flex bison \ libvte-2.91-dev \ libxen-dev \ make \ - python-yaml \ + python3-yaml \ python3-sphinx \ sparse \ texinfo \ diff --git a/tests/docker/test-clang b/tests/docker/test-clang index 324e341cea..8c51ead518 100755 --- a/tests/docker/test-clang +++ b/tests/docker/test-clang @@ -18,10 +18,8 @@ requires clang cd "$BUILD_DIR" OPTS="--cxx=clang++ --cc=clang --host-cc=clang" -# -fsanitize=undefined is broken on Fedora 23, skip it for now -# See also: https://bugzilla.redhat.com/show_bug.cgi?id=1263834 -#OPTS="$OPTS --extra-cflags=-fsanitize=undefined \ - #--extra-cflags=-fno-sanitize=float-divide-by-zero" +OPTS="$OPTS --extra-cflags=-fsanitize=undefined \ + --extra-cflags=-fno-sanitize=float-divide-by-zero" build_qemu $OPTS check_qemu install_qemu diff --git a/tests/docker/test-debug b/tests/docker/test-debug index 137f4f2ddc..c050fa0d93 100755 --- a/tests/docker/test-debug +++ b/tests/docker/test-debug @@ -21,6 +21,7 @@ cd "$BUILD_DIR" OPTS="--cxx=clang++ --cc=clang --host-cc=clang" OPTS="--enable-debug --enable-sanitizers $OPTS" +export ASAN_OPTIONS=detect_leaks=0 build_qemu $OPTS check_qemu check V=1 install_qemu diff --git a/tests/migration-test.c b/tests/migration-test.c index 258aa064d4..59f291c654 100644 --- a/tests/migration-test.c +++ b/tests/migration-test.c @@ -240,6 +240,17 @@ static int64_t read_ram_property_int(QTestState *who, const char *property) return result; } +static int64_t read_migrate_property_int(QTestState *who, const char *property) +{ + QDict *rsp_return; + int64_t result; + + rsp_return = migrate_query(who); + result = qdict_get_try_int(rsp_return, property, 0); + qobject_unref(rsp_return); + return result; +} + static uint64_t get_migration_pass(QTestState *who) { return read_ram_property_int(who, "dirty-sync-count"); @@ -254,27 +265,46 @@ static void read_blocktime(QTestState *who) qobject_unref(rsp_return); } -static void wait_for_migration_status(QTestState *who, - const char *goal) +static bool check_migration_status(QTestState *who, const char *goal, + const char **ungoals) { - while (true) { - bool completed; - char *status; - - status = migrate_query_status(who); - completed = strcmp(status, goal) == 0; - g_assert_cmpstr(status, !=, "failed"); - g_free(status); - if (completed) { - return; + bool ready; + char *current_status; + const char **ungoal; + + current_status = migrate_query_status(who); + ready = strcmp(current_status, goal) == 0; + if (!ungoals) { + g_assert_cmpstr(current_status, !=, "failed"); + /* + * If looking for a state other than completed, + * completion of migration would cause the test to + * hang. + */ + if (strcmp(goal, "completed") != 0) { + g_assert_cmpstr(current_status, !=, "completed"); } + } else { + for (ungoal = ungoals; *ungoal; ungoal++) { + g_assert_cmpstr(current_status, !=, *ungoal); + } + } + g_free(current_status); + return ready; +} + +static void wait_for_migration_status(QTestState *who, + const char *goal, + const char **ungoals) +{ + while (!check_migration_status(who, goal, ungoals)) { usleep(1000); } } static void wait_for_migration_complete(QTestState *who) { - wait_for_migration_status(who, "completed"); + wait_for_migration_status(who, "completed", NULL); } static void wait_for_migration_pass(QTestState *who) @@ -445,6 +475,17 @@ static void migrate_pause(QTestState *who) qobject_unref(rsp); } +static void migrate_continue(QTestState *who, const char *state) +{ + QDict *rsp; + + rsp = wait_command(who, + "{ 'execute': 'migrate-continue'," + " 'arguments': { 'state': %s } }", + state); + qobject_unref(rsp); +} + static void migrate_recover(QTestState *who, const char *uri) { QDict *rsp; @@ -748,7 +789,7 @@ static int migrate_postcopy_prepare(QTestState **from_ptr, * quickly, but that it doesn't complete precopy even on a slow * machine, so also set the downtime. */ - migrate_set_parameter_int(from, "max-bandwidth", 100000000); + migrate_set_parameter_int(from, "max-bandwidth", 30000000); migrate_set_parameter_int(from, "downtime-limit", 1); /* Wait for the first serial output from the source */ @@ -809,7 +850,7 @@ static void test_postcopy_recovery(void) * Wait until postcopy is really started; we can only run the * migrate-pause command during a postcopy */ - wait_for_migration_status(from, "postcopy-active"); + wait_for_migration_status(from, "postcopy-active", NULL); /* * Manually stop the postcopy migration. This emulates a network @@ -822,7 +863,9 @@ static void test_postcopy_recovery(void) * migrate-recover command can only succeed if destination machine * is in the paused state */ - wait_for_migration_status(to, "postcopy-paused"); + wait_for_migration_status(to, "postcopy-paused", + (const char * []) { "failed", "active", + "completed", NULL }); /* * Create a new socket to emulate a new channel that is different @@ -836,7 +879,9 @@ static void test_postcopy_recovery(void) * Try to rebuild the migration channel using the resume flag and * the newly created channel */ - wait_for_migration_status(from, "postcopy-paused"); + wait_for_migration_status(from, "postcopy-paused", + (const char * []) { "failed", "active", + "completed", NULL }); migrate(from, uri, "{'resume': true}"); g_free(uri); @@ -1199,6 +1244,89 @@ static void test_validate_uuid_dst_not_set(void) false, true); } +static void test_migrate_auto_converge(void) +{ + char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + QTestState *from, *to; + int64_t remaining, percentage; + + /* + * We want the test to be stable and as fast as possible. + * E.g., with 1Gb/s bandwith migration may pass without throttling, + * so we need to decrease a bandwidth. + */ + const int64_t init_pct = 5, inc_pct = 50, max_pct = 95; + const int64_t max_bandwidth = 400000000; /* ~400Mb/s */ + const int64_t downtime_limit = 250; /* 250ms */ + /* + * We migrate through unix-socket (> 500Mb/s). + * Thus, expected migration speed ~= bandwidth limit (< 500Mb/s). + * So, we can predict expected_threshold + */ + const int64_t expected_threshold = max_bandwidth * downtime_limit / 1000; + + if (test_migrate_start(&from, &to, uri, false, false, NULL, NULL)) { + return; + } + + migrate_set_capability(from, "auto-converge", true); + migrate_set_parameter_int(from, "cpu-throttle-initial", init_pct); + migrate_set_parameter_int(from, "cpu-throttle-increment", inc_pct); + migrate_set_parameter_int(from, "max-cpu-throttle", max_pct); + + /* + * Set the initial parameters so that the migration could not converge + * without throttling. + */ + migrate_set_parameter_int(from, "downtime-limit", 1); + migrate_set_parameter_int(from, "max-bandwidth", 100000000); /* ~100Mb/s */ + + /* To check remaining size after precopy */ + migrate_set_capability(from, "pause-before-switchover", true); + + /* Wait for the first serial output from the source */ + wait_for_serial("src_serial"); + + migrate(from, uri, "{}"); + + /* Wait for throttling begins */ + percentage = 0; + while (percentage == 0) { + percentage = read_migrate_property_int(from, "cpu-throttle-percentage"); + usleep(100); + g_assert_false(got_stop); + } + /* The first percentage of throttling should be equal to init_pct */ + g_assert_cmpint(percentage, ==, init_pct); + /* Now, when we tested that throttling works, let it converge */ + migrate_set_parameter_int(from, "downtime-limit", downtime_limit); + migrate_set_parameter_int(from, "max-bandwidth", max_bandwidth); + + /* + * Wait for pre-switchover status to check last throttle percentage + * and remaining. These values will be zeroed later + */ + wait_for_migration_status(from, "pre-switchover", NULL); + + /* The final percentage of throttling shouldn't be greater than max_pct */ + percentage = read_migrate_property_int(from, "cpu-throttle-percentage"); + g_assert_cmpint(percentage, <=, max_pct); + + remaining = read_ram_property_int(from, "remaining"); + g_assert_cmpint(remaining, <, expected_threshold); + + migrate_continue(from, "pre-switchover"); + + qtest_qmp_eventwait(to, "RESUME"); + + wait_for_serial("dest_serial"); + wait_for_migration_complete(from); + + g_free(uri); + + test_migrate_end(from, to, true); +} + int main(int argc, char **argv) { char template[] = "/tmp/migration-test-XXXXXX"; @@ -1261,6 +1389,8 @@ int main(int argc, char **argv) qtest_add_func("/migration/validate_uuid_dst_not_set", test_validate_uuid_dst_not_set); + qtest_add_func("/migration/auto_converge", test_migrate_auto_converge); + ret = g_test_run(); g_assert_cmpint(ret, ==, 0); diff --git a/tests/qapi-schema/allow-preconfig-test.err b/tests/qapi-schema/allow-preconfig-test.err index 700d583306..2a4e6ce663 100644 --- a/tests/qapi-schema/allow-preconfig-test.err +++ b/tests/qapi-schema/allow-preconfig-test.err @@ -1 +1,2 @@ -tests/qapi-schema/allow-preconfig-test.json:2: 'allow-preconfig' of command 'allow-preconfig-test' should only use true value +tests/qapi-schema/allow-preconfig-test.json: In command 'allow-preconfig-test': +tests/qapi-schema/allow-preconfig-test.json:2: flag 'allow-preconfig' may only use true value diff --git a/tests/qapi-schema/alternate-any.err b/tests/qapi-schema/alternate-any.err index aaa0154731..03aaf29506 100644 --- a/tests/qapi-schema/alternate-any.err +++ b/tests/qapi-schema/alternate-any.err @@ -1 +1,2 @@ -tests/qapi-schema/alternate-any.json:2: Alternate 'Alt' member 'one' cannot use type 'any' +tests/qapi-schema/alternate-any.json: In alternate 'Alt': +tests/qapi-schema/alternate-any.json:2: branch 'one' cannot use built-in type 'any' diff --git a/tests/qapi-schema/alternate-array.err b/tests/qapi-schema/alternate-array.err index 7b930c64ab..dfbe3ee998 100644 --- a/tests/qapi-schema/alternate-array.err +++ b/tests/qapi-schema/alternate-array.err @@ -1 +1,2 @@ -tests/qapi-schema/alternate-array.json:5: Member 'two' of alternate 'Alt' cannot be an array +tests/qapi-schema/alternate-array.json: In alternate 'Alt': +tests/qapi-schema/alternate-array.json:5: 'data' member 'two' cannot be an array diff --git a/tests/qapi-schema/alternate-base.err b/tests/qapi-schema/alternate-base.err index ebe05bc898..04cea97e5c 100644 --- a/tests/qapi-schema/alternate-base.err +++ b/tests/qapi-schema/alternate-base.err @@ -1,2 +1,3 @@ -tests/qapi-schema/alternate-base.json:4: Unknown key 'base' in alternate 'Alt' +tests/qapi-schema/alternate-base.json: In alternate 'Alt': +tests/qapi-schema/alternate-base.json:4: alternate has unknown key 'base' Valid keys are 'alternate', 'data', 'if'. diff --git a/tests/qapi-schema/alternate-branch-if-invalid.err b/tests/qapi-schema/alternate-branch-if-invalid.err new file mode 100644 index 0000000000..6c68e5a922 --- /dev/null +++ b/tests/qapi-schema/alternate-branch-if-invalid.err @@ -0,0 +1,2 @@ +tests/qapi-schema/alternate-branch-if-invalid.json: In alternate 'Alt': +tests/qapi-schema/alternate-branch-if-invalid.json:2: 'if' condition ' ' of 'data' member 'branch' makes no sense diff --git a/tests/qapi-schema/args-boxed-empty.exit b/tests/qapi-schema/alternate-branch-if-invalid.exit index d00491fd7e..d00491fd7e 100644 --- a/tests/qapi-schema/args-boxed-empty.exit +++ b/tests/qapi-schema/alternate-branch-if-invalid.exit diff --git a/tests/qapi-schema/alternate-branch-if-invalid.json b/tests/qapi-schema/alternate-branch-if-invalid.json new file mode 100644 index 0000000000..fea6d9080c --- /dev/null +++ b/tests/qapi-schema/alternate-branch-if-invalid.json @@ -0,0 +1,3 @@ +# Cover alternative with invalid 'if' +{ 'alternate': 'Alt', + 'data': { 'branch': { 'type': 'int', 'if': ' ' } } } diff --git a/tests/qapi-schema/args-boxed-empty.out b/tests/qapi-schema/alternate-branch-if-invalid.out index e69de29bb2..e69de29bb2 100644 --- a/tests/qapi-schema/args-boxed-empty.out +++ b/tests/qapi-schema/alternate-branch-if-invalid.out diff --git a/tests/qapi-schema/alternate-clash.err b/tests/qapi-schema/alternate-clash.err index 604d8495eb..73a52d69d1 100644 --- a/tests/qapi-schema/alternate-clash.err +++ b/tests/qapi-schema/alternate-clash.err @@ -1 +1,2 @@ -tests/qapi-schema/alternate-clash.json:7: 'a_b' (branch of Alt1) collides with 'a-b' (branch of Alt1) +tests/qapi-schema/alternate-clash.json: In alternate 'Alt1': +tests/qapi-schema/alternate-clash.json:7: branch 'a_b' collides with branch 'a-b' diff --git a/tests/qapi-schema/alternate-conflict-bool-string.err b/tests/qapi-schema/alternate-conflict-bool-string.err index e52fee7620..f7513b9cbe 100644 --- a/tests/qapi-schema/alternate-conflict-bool-string.err +++ b/tests/qapi-schema/alternate-conflict-bool-string.err @@ -1 +1,2 @@ -tests/qapi-schema/alternate-conflict-bool-string.json:2: Alternate 'Alt' member 'two' can't be distinguished from member 'one' +tests/qapi-schema/alternate-conflict-bool-string.json: In alternate 'Alt': +tests/qapi-schema/alternate-conflict-bool-string.json:2: branch 'two' can't be distinguished from 'one' diff --git a/tests/qapi-schema/alternate-conflict-dict.err b/tests/qapi-schema/alternate-conflict-dict.err index 0f411f4faf..e5b42d04c9 100644 --- a/tests/qapi-schema/alternate-conflict-dict.err +++ b/tests/qapi-schema/alternate-conflict-dict.err @@ -1 +1,2 @@ -tests/qapi-schema/alternate-conflict-dict.json:6: Alternate 'Alt' member 'two' can't be distinguished from member 'one' +tests/qapi-schema/alternate-conflict-dict.json: In alternate 'Alt': +tests/qapi-schema/alternate-conflict-dict.json:6: branch 'two' can't be distinguished from 'one' diff --git a/tests/qapi-schema/alternate-conflict-enum-bool.err b/tests/qapi-schema/alternate-conflict-enum-bool.err index 0dfc00242d..3d23aeba51 100644 --- a/tests/qapi-schema/alternate-conflict-enum-bool.err +++ b/tests/qapi-schema/alternate-conflict-enum-bool.err @@ -1 +1,2 @@ -tests/qapi-schema/alternate-conflict-enum-bool.json:4: Alternate 'Alt' member 'two' can't be distinguished from member 'one' +tests/qapi-schema/alternate-conflict-enum-bool.json: In alternate 'Alt': +tests/qapi-schema/alternate-conflict-enum-bool.json:4: branch 'two' can't be distinguished from 'one' diff --git a/tests/qapi-schema/alternate-conflict-enum-int.err b/tests/qapi-schema/alternate-conflict-enum-int.err index 2cc8e7b9aa..b72768caa4 100644 --- a/tests/qapi-schema/alternate-conflict-enum-int.err +++ b/tests/qapi-schema/alternate-conflict-enum-int.err @@ -1 +1,2 @@ -tests/qapi-schema/alternate-conflict-enum-int.json:4: Alternate 'Alt' member 'two' can't be distinguished from member 'one' +tests/qapi-schema/alternate-conflict-enum-int.json: In alternate 'Alt': +tests/qapi-schema/alternate-conflict-enum-int.json:4: branch 'two' can't be distinguished from 'one' diff --git a/tests/qapi-schema/alternate-conflict-num-string.err b/tests/qapi-schema/alternate-conflict-num-string.err index 5ba3827dd1..b8a2bb1829 100644 --- a/tests/qapi-schema/alternate-conflict-num-string.err +++ b/tests/qapi-schema/alternate-conflict-num-string.err @@ -1 +1,2 @@ -tests/qapi-schema/alternate-conflict-num-string.json:2: Alternate 'Alt' member 'two' can't be distinguished from member 'one' +tests/qapi-schema/alternate-conflict-num-string.json: In alternate 'Alt': +tests/qapi-schema/alternate-conflict-num-string.json:2: branch 'two' can't be distinguished from 'one' diff --git a/tests/qapi-schema/alternate-conflict-string.err b/tests/qapi-schema/alternate-conflict-string.err index fe2f188295..3edec51911 100644 --- a/tests/qapi-schema/alternate-conflict-string.err +++ b/tests/qapi-schema/alternate-conflict-string.err @@ -1 +1,2 @@ -tests/qapi-schema/alternate-conflict-string.json:2: Alternate 'Alt' member 'two' can't be distinguished from member 'one' +tests/qapi-schema/alternate-conflict-string.json: In alternate 'Alt': +tests/qapi-schema/alternate-conflict-string.json:2: branch 'two' can't be distinguished from 'one' diff --git a/tests/qapi-schema/alternate-empty.err b/tests/qapi-schema/alternate-empty.err index bb06c5bfec..908c309518 100644 --- a/tests/qapi-schema/alternate-empty.err +++ b/tests/qapi-schema/alternate-empty.err @@ -1 +1,2 @@ -tests/qapi-schema/alternate-empty.json:2: Alternate 'Alt' should have at least two branches in 'data' +tests/qapi-schema/alternate-empty.json: In alternate 'Alt': +tests/qapi-schema/alternate-empty.json:2: 'data' must not be empty diff --git a/tests/qapi-schema/alternate-empty.json b/tests/qapi-schema/alternate-empty.json index fff15baf16..9f445474e6 100644 --- a/tests/qapi-schema/alternate-empty.json +++ b/tests/qapi-schema/alternate-empty.json @@ -1,2 +1,2 @@ -# alternates must list at least two types to be useful -{ 'alternate': 'Alt', 'data': { 'i': 'int' } } +# alternates cannot be empty +{ 'alternate': 'Alt', 'data': { } } diff --git a/tests/qapi-schema/alternate-invalid-dict.err b/tests/qapi-schema/alternate-invalid-dict.err index 631d46628e..d6a18a294b 100644 --- a/tests/qapi-schema/alternate-invalid-dict.err +++ b/tests/qapi-schema/alternate-invalid-dict.err @@ -1 +1,2 @@ -tests/qapi-schema/alternate-invalid-dict.json:2: Key 'type' is missing from member 'two' of alternate 'Alt' +tests/qapi-schema/alternate-invalid-dict.json: In alternate 'Alt': +tests/qapi-schema/alternate-invalid-dict.json:2: 'data' member 'two' misses key 'type' diff --git a/tests/qapi-schema/alternate-nested.err b/tests/qapi-schema/alternate-nested.err index 4d1187e60e..cd7a076ce5 100644 --- a/tests/qapi-schema/alternate-nested.err +++ b/tests/qapi-schema/alternate-nested.err @@ -1 +1,2 @@ -tests/qapi-schema/alternate-nested.json:4: Member 'nested' of alternate 'Alt2' cannot use alternate type 'Alt1' +tests/qapi-schema/alternate-nested.json: In alternate 'Alt2': +tests/qapi-schema/alternate-nested.json:4: branch 'nested' cannot use alternate type 'Alt1' diff --git a/tests/qapi-schema/alternate-unknown.err b/tests/qapi-schema/alternate-unknown.err index dea45dc730..df05860bba 100644 --- a/tests/qapi-schema/alternate-unknown.err +++ b/tests/qapi-schema/alternate-unknown.err @@ -1 +1,2 @@ -tests/qapi-schema/alternate-unknown.json:2: Member 'unknown' of alternate 'Alt' uses unknown type 'MissingType' +tests/qapi-schema/alternate-unknown.json: In alternate 'Alt': +tests/qapi-schema/alternate-unknown.json:2: branch 'unknown' uses unknown type 'MissingType' diff --git a/tests/qapi-schema/args-alternate.err b/tests/qapi-schema/args-alternate.err index 3086eae56b..852b81b89c 100644 --- a/tests/qapi-schema/args-alternate.err +++ b/tests/qapi-schema/args-alternate.err @@ -1 +1,2 @@ -tests/qapi-schema/args-alternate.json:3: 'data' for command 'oops' cannot use alternate type 'Alt' +tests/qapi-schema/args-alternate.json: In command 'oops': +tests/qapi-schema/args-alternate.json:3: command's 'data' cannot take alternate type 'Alt' diff --git a/tests/qapi-schema/args-any.err b/tests/qapi-schema/args-any.err index bf9b5e0730..04e11df29f 100644 --- a/tests/qapi-schema/args-any.err +++ b/tests/qapi-schema/args-any.err @@ -1 +1,2 @@ -tests/qapi-schema/args-any.json:2: 'data' for command 'oops' cannot use built-in type 'any' +tests/qapi-schema/args-any.json: In command 'oops': +tests/qapi-schema/args-any.json:2: command's 'data' cannot take built-in type 'any' diff --git a/tests/qapi-schema/args-array-empty.err b/tests/qapi-schema/args-array-empty.err index cb7ed33b3f..c7d367730e 100644 --- a/tests/qapi-schema/args-array-empty.err +++ b/tests/qapi-schema/args-array-empty.err @@ -1 +1,2 @@ -tests/qapi-schema/args-array-empty.json:2: Member 'empty' of 'data' for command 'oops': array type must contain single type name +tests/qapi-schema/args-array-empty.json: In command 'oops': +tests/qapi-schema/args-array-empty.json:2: 'data' member 'empty': array type must contain single type name diff --git a/tests/qapi-schema/args-array-unknown.err b/tests/qapi-schema/args-array-unknown.err index cd7a0f98d7..218fc4bf9a 100644 --- a/tests/qapi-schema/args-array-unknown.err +++ b/tests/qapi-schema/args-array-unknown.err @@ -1 +1,2 @@ -tests/qapi-schema/args-array-unknown.json:2: Member 'array' of 'data' for command 'oops' uses unknown type 'NoSuchType' +tests/qapi-schema/args-array-unknown.json: In command 'oops': +tests/qapi-schema/args-array-unknown.json:2: command uses unknown type 'NoSuchType' diff --git a/tests/qapi-schema/args-bad-boxed.err b/tests/qapi-schema/args-bad-boxed.err index ad0d417321..31d39038fc 100644 --- a/tests/qapi-schema/args-bad-boxed.err +++ b/tests/qapi-schema/args-bad-boxed.err @@ -1 +1,2 @@ -tests/qapi-schema/args-bad-boxed.json:2: 'boxed' of command 'foo' should only use true value +tests/qapi-schema/args-bad-boxed.json: In command 'foo': +tests/qapi-schema/args-bad-boxed.json:2: flag 'boxed' may only use true value diff --git a/tests/qapi-schema/args-boxed-anon.err b/tests/qapi-schema/args-boxed-anon.err index f24f345218..5e0c2979b7 100644 --- a/tests/qapi-schema/args-boxed-anon.err +++ b/tests/qapi-schema/args-boxed-anon.err @@ -1 +1,2 @@ -tests/qapi-schema/args-boxed-anon.json:2: 'data' for command 'foo' should be a type name +tests/qapi-schema/args-boxed-anon.json: In command 'foo': +tests/qapi-schema/args-boxed-anon.json:2: 'data' should be a type name diff --git a/tests/qapi-schema/args-boxed-empty.err b/tests/qapi-schema/args-boxed-empty.err deleted file mode 100644 index 039603e85c..0000000000 --- a/tests/qapi-schema/args-boxed-empty.err +++ /dev/null @@ -1 +0,0 @@ -tests/qapi-schema/args-boxed-empty.json:3: Cannot use 'boxed' with empty type diff --git a/tests/qapi-schema/args-boxed-empty.json b/tests/qapi-schema/args-boxed-empty.json deleted file mode 100644 index 52717e065f..0000000000 --- a/tests/qapi-schema/args-boxed-empty.json +++ /dev/null @@ -1,3 +0,0 @@ -# 'boxed' requires a non-empty type -{ 'struct': 'Empty', 'data': {} } -{ 'command': 'foo', 'boxed': true, 'data': 'Empty' } diff --git a/tests/qapi-schema/args-boxed-string.err b/tests/qapi-schema/args-boxed-string.err index d326b48aef..dc2b00f217 100644 --- a/tests/qapi-schema/args-boxed-string.err +++ b/tests/qapi-schema/args-boxed-string.err @@ -1 +1,2 @@ -tests/qapi-schema/args-boxed-string.json:2: 'data' for command 'foo' cannot use built-in type 'str' +tests/qapi-schema/args-boxed-string.json: In command 'foo': +tests/qapi-schema/args-boxed-string.json:2: command's 'data' cannot take built-in type 'str' diff --git a/tests/qapi-schema/args-int.err b/tests/qapi-schema/args-int.err index dc1d2504ff..81b6f86b66 100644 --- a/tests/qapi-schema/args-int.err +++ b/tests/qapi-schema/args-int.err @@ -1 +1,2 @@ -tests/qapi-schema/args-int.json:2: 'data' for command 'oops' cannot use built-in type 'int' +tests/qapi-schema/args-int.json: In command 'oops': +tests/qapi-schema/args-int.json:2: command's 'data' cannot take built-in type 'int' diff --git a/tests/qapi-schema/args-invalid.err b/tests/qapi-schema/args-invalid.err index fe1e94975b..c4971e1399 100644 --- a/tests/qapi-schema/args-invalid.err +++ b/tests/qapi-schema/args-invalid.err @@ -1 +1,2 @@ -tests/qapi-schema/args-invalid.json:1: 'data' for command 'foo' should be a dictionary or type name +tests/qapi-schema/args-invalid.json: In command 'foo': +tests/qapi-schema/args-invalid.json:1: 'data' should be an object or type name diff --git a/tests/qapi-schema/args-member-array-bad.err b/tests/qapi-schema/args-member-array-bad.err index 881b4d954f..f95ac01372 100644 --- a/tests/qapi-schema/args-member-array-bad.err +++ b/tests/qapi-schema/args-member-array-bad.err @@ -1 +1,2 @@ -tests/qapi-schema/args-member-array-bad.json:2: Member 'member' of 'data' for command 'oops': array type must contain single type name +tests/qapi-schema/args-member-array-bad.json: In command 'oops': +tests/qapi-schema/args-member-array-bad.json:2: 'data' member 'member': array type must contain single type name diff --git a/tests/qapi-schema/args-member-case.err b/tests/qapi-schema/args-member-case.err index 19c4426601..3ecd276040 100644 --- a/tests/qapi-schema/args-member-case.err +++ b/tests/qapi-schema/args-member-case.err @@ -1 +1,2 @@ -tests/qapi-schema/args-member-case.json:2: 'Arg' (parameter of no-way-this-will-get-whitelisted) should not use uppercase +tests/qapi-schema/args-member-case.json: In command 'no-way-this-will-get-whitelisted': +tests/qapi-schema/args-member-case.json:2: 'data' member 'Arg' uses uppercase in name diff --git a/tests/qapi-schema/args-member-case.json b/tests/qapi-schema/args-member-case.json index 93439bee8b..e27c603548 100644 --- a/tests/qapi-schema/args-member-case.json +++ b/tests/qapi-schema/args-member-case.json @@ -1,2 +1,2 @@ -# Member names should be 'lower-case' unless the struct/command is whitelisted +# Member names should be 'lower-case' unless the struct is whitelisted { 'command': 'no-way-this-will-get-whitelisted', 'data': { 'Arg': 'int' } } diff --git a/tests/qapi-schema/args-member-unknown.err b/tests/qapi-schema/args-member-unknown.err index f6f82828ce..0626e1209d 100644 --- a/tests/qapi-schema/args-member-unknown.err +++ b/tests/qapi-schema/args-member-unknown.err @@ -1 +1,2 @@ -tests/qapi-schema/args-member-unknown.json:2: Member 'member' of 'data' for command 'oops' uses unknown type 'NoSuchType' +tests/qapi-schema/args-member-unknown.json: In command 'oops': +tests/qapi-schema/args-member-unknown.json:2: parameter 'member' uses unknown type 'NoSuchType' diff --git a/tests/qapi-schema/args-name-clash.err b/tests/qapi-schema/args-name-clash.err index d953e8d241..c5916a80fb 100644 --- a/tests/qapi-schema/args-name-clash.err +++ b/tests/qapi-schema/args-name-clash.err @@ -1 +1,2 @@ -tests/qapi-schema/args-name-clash.json:4: 'a_b' (parameter of oops) collides with 'a-b' (parameter of oops) +tests/qapi-schema/args-name-clash.json: In command 'oops': +tests/qapi-schema/args-name-clash.json:4: parameter 'a_b' collides with parameter 'a-b' diff --git a/tests/qapi-schema/args-union.err b/tests/qapi-schema/args-union.err index f8ad223dde..3a77b2863f 100644 --- a/tests/qapi-schema/args-union.err +++ b/tests/qapi-schema/args-union.err @@ -1 +1,2 @@ -tests/qapi-schema/args-union.json:3: 'data' for command 'oops' cannot use union type 'Uni' +tests/qapi-schema/args-union.json: In command 'oops': +tests/qapi-schema/args-union.json:3: command's 'data' can take union type 'Uni' only with 'boxed': true diff --git a/tests/qapi-schema/args-unknown.err b/tests/qapi-schema/args-unknown.err index 4d91ec869f..6857d6bf48 100644 --- a/tests/qapi-schema/args-unknown.err +++ b/tests/qapi-schema/args-unknown.err @@ -1 +1,2 @@ -tests/qapi-schema/args-unknown.json:2: 'data' for command 'oops' uses unknown type 'NoSuchType' +tests/qapi-schema/args-unknown.json: In command 'oops': +tests/qapi-schema/args-unknown.json:2: command's 'data' uses unknown type 'NoSuchType' diff --git a/tests/qapi-schema/bad-base.err b/tests/qapi-schema/bad-base.err index 154274bdd3..039678a364 100644 --- a/tests/qapi-schema/bad-base.err +++ b/tests/qapi-schema/bad-base.err @@ -1 +1,2 @@ -tests/qapi-schema/bad-base.json:3: 'base' for struct 'MyType' cannot use union type 'Union' +tests/qapi-schema/bad-base.json: In struct 'MyType': +tests/qapi-schema/bad-base.json:3: 'base' requires a struct type, union type 'Union' isn't diff --git a/tests/qapi-schema/bad-data.err b/tests/qapi-schema/bad-data.err index 8523ac4f46..5227bdce7e 100644 --- a/tests/qapi-schema/bad-data.err +++ b/tests/qapi-schema/bad-data.err @@ -1 +1,2 @@ -tests/qapi-schema/bad-data.json:2: 'data' for command 'oops' cannot be an array +tests/qapi-schema/bad-data.json: In command 'oops': +tests/qapi-schema/bad-data.json:2: 'data' cannot be an array diff --git a/tests/qapi-schema/bad-ident.err b/tests/qapi-schema/bad-ident.err index c4190602b5..ad38a679c7 100644 --- a/tests/qapi-schema/bad-ident.err +++ b/tests/qapi-schema/bad-ident.err @@ -1 +1,2 @@ -tests/qapi-schema/bad-ident.json:2: 'struct' does not allow optional name '*oops' +tests/qapi-schema/bad-ident.json: In struct '*oops': +tests/qapi-schema/bad-ident.json:2: struct has an invalid name diff --git a/tests/qapi-schema/bad-if-empty-list.err b/tests/qapi-schema/bad-if-empty-list.err index 75fe6497bc..517519f500 100644 --- a/tests/qapi-schema/bad-if-empty-list.err +++ b/tests/qapi-schema/bad-if-empty-list.err @@ -1 +1,2 @@ -tests/qapi-schema/bad-if-empty-list.json:2: 'if' condition [] is useless +tests/qapi-schema/bad-if-empty-list.json: In struct 'TestIfStruct': +tests/qapi-schema/bad-if-empty-list.json:2: 'if' condition [] of struct is useless diff --git a/tests/qapi-schema/bad-if-empty.err b/tests/qapi-schema/bad-if-empty.err index 358bdc3e51..5f1767388e 100644 --- a/tests/qapi-schema/bad-if-empty.err +++ b/tests/qapi-schema/bad-if-empty.err @@ -1 +1,2 @@ -tests/qapi-schema/bad-if-empty.json:2: 'if' condition '' makes no sense +tests/qapi-schema/bad-if-empty.json: In struct 'TestIfStruct': +tests/qapi-schema/bad-if-empty.json:2: 'if' condition '' of struct makes no sense diff --git a/tests/qapi-schema/bad-if-list.err b/tests/qapi-schema/bad-if-list.err index 0af6316f78..e5d72b2f39 100644 --- a/tests/qapi-schema/bad-if-list.err +++ b/tests/qapi-schema/bad-if-list.err @@ -1 +1,2 @@ -tests/qapi-schema/bad-if-list.json:2: 'if' condition '' makes no sense +tests/qapi-schema/bad-if-list.json: In struct 'TestIfStruct': +tests/qapi-schema/bad-if-list.json:2: 'if' condition ' ' of struct makes no sense diff --git a/tests/qapi-schema/bad-if-list.json b/tests/qapi-schema/bad-if-list.json index 49ced9b9ca..ea3d95bb6b 100644 --- a/tests/qapi-schema/bad-if-list.json +++ b/tests/qapi-schema/bad-if-list.json @@ -1,3 +1,3 @@ # check invalid 'if' content { 'struct': 'TestIfStruct', 'data': { 'foo': 'int' }, - 'if': ['foo', ''] } + 'if': ['foo', ' '] } diff --git a/tests/qapi-schema/bad-if.err b/tests/qapi-schema/bad-if.err index c2e3f5f44c..65d8efd7e4 100644 --- a/tests/qapi-schema/bad-if.err +++ b/tests/qapi-schema/bad-if.err @@ -1 +1,2 @@ -tests/qapi-schema/bad-if.json:2: 'if' condition must be a string or a list of strings +tests/qapi-schema/bad-if.json: In struct 'TestIfStruct': +tests/qapi-schema/bad-if.json:2: 'if' condition of struct must be a string or a list of strings diff --git a/tests/qapi-schema/bad-type-bool.err b/tests/qapi-schema/bad-type-bool.err index 62fd70baaf..984a77c4e3 100644 --- a/tests/qapi-schema/bad-type-bool.err +++ b/tests/qapi-schema/bad-type-bool.err @@ -1 +1 @@ -tests/qapi-schema/bad-type-bool.json:2: 'struct' key must have a string value +tests/qapi-schema/bad-type-bool.json:2: 'struct' requires a string name diff --git a/tests/qapi-schema/bad-type-dict.err b/tests/qapi-schema/bad-type-dict.err index 0b2a2aeac4..e83b8cfb41 100644 --- a/tests/qapi-schema/bad-type-dict.err +++ b/tests/qapi-schema/bad-type-dict.err @@ -1 +1 @@ -tests/qapi-schema/bad-type-dict.json:2: 'command' key must have a string value +tests/qapi-schema/bad-type-dict.json:2: 'command' requires a string name diff --git a/tests/qapi-schema/bad-type-int.err b/tests/qapi-schema/bad-type-int.err index da89895404..7f5916ea29 100644 --- a/tests/qapi-schema/bad-type-int.err +++ b/tests/qapi-schema/bad-type-int.err @@ -1 +1 @@ -tests/qapi-schema/bad-type-int.json:3:13: Stray "1" +tests/qapi-schema/bad-type-int.json:3:13: stray '123' diff --git a/tests/qapi-schema/bad-type-int.json b/tests/qapi-schema/bad-type-int.json index 56fc6f8126..f3ad803cb6 100644 --- a/tests/qapi-schema/bad-type-int.json +++ b/tests/qapi-schema/bad-type-int.json @@ -1,3 +1,3 @@ # we reject an expression with a metatype that is not a string # FIXME: once the parser understands integer inputs, improve the error message -{ 'struct': 1, 'data': { } } +{ 'struct': 123, 'data': { } } diff --git a/tests/qapi-schema/base-cycle-direct.err b/tests/qapi-schema/base-cycle-direct.err index 9c68f6543d..233e4b8952 100644 --- a/tests/qapi-schema/base-cycle-direct.err +++ b/tests/qapi-schema/base-cycle-direct.err @@ -1 +1,2 @@ -tests/qapi-schema/base-cycle-direct.json:2: Object Loopy contains itself +tests/qapi-schema/base-cycle-direct.json: In struct 'Loopy': +tests/qapi-schema/base-cycle-direct.json:2: object Loopy contains itself diff --git a/tests/qapi-schema/base-cycle-indirect.err b/tests/qapi-schema/base-cycle-indirect.err index fc92fe47f8..4472f30ba1 100644 --- a/tests/qapi-schema/base-cycle-indirect.err +++ b/tests/qapi-schema/base-cycle-indirect.err @@ -1 +1,2 @@ -tests/qapi-schema/base-cycle-indirect.json:2: Object Base1 contains itself +tests/qapi-schema/base-cycle-indirect.json: In struct 'Base1': +tests/qapi-schema/base-cycle-indirect.json:2: object Base1 contains itself diff --git a/tests/qapi-schema/command-int.err b/tests/qapi-schema/command-int.err index 0f9300679b..3523d50a79 100644 --- a/tests/qapi-schema/command-int.err +++ b/tests/qapi-schema/command-int.err @@ -1 +1,2 @@ -tests/qapi-schema/command-int.json:2: built-in 'int' is already defined +tests/qapi-schema/command-int.json: In command 'int': +tests/qapi-schema/command-int.json:2: built-in type 'int' is already defined diff --git a/tests/qapi-schema/doc-bad-alternate-member.err b/tests/qapi-schema/doc-bad-alternate-member.err index 387f7824da..19a1ffd76e 100644 --- a/tests/qapi-schema/doc-bad-alternate-member.err +++ b/tests/qapi-schema/doc-bad-alternate-member.err @@ -1 +1 @@ -tests/qapi-schema/doc-bad-alternate-member.json:3: The following documented members are not in the declaration: aa, bb +tests/qapi-schema/doc-bad-alternate-member.json:3: the following documented members are not in the declaration: aa, bb diff --git a/tests/qapi-schema/doc-bad-command-arg.err b/tests/qapi-schema/doc-bad-command-arg.err index 8075b146ae..6962ebed69 100644 --- a/tests/qapi-schema/doc-bad-command-arg.err +++ b/tests/qapi-schema/doc-bad-command-arg.err @@ -1 +1 @@ -tests/qapi-schema/doc-bad-command-arg.json:3: The following documented members are not in the declaration: b +tests/qapi-schema/doc-bad-command-arg.json:3: the following documented members are not in the declaration: b diff --git a/tests/qapi-schema/doc-bad-symbol.err b/tests/qapi-schema/doc-bad-symbol.err index 8472030c79..b23e99d160 100644 --- a/tests/qapi-schema/doc-bad-symbol.err +++ b/tests/qapi-schema/doc-bad-symbol.err @@ -1 +1,2 @@ -tests/qapi-schema/doc-bad-symbol.json:6: Definition of 'foo' follows documentation for 'food' +tests/qapi-schema/doc-bad-symbol.json: In command 'foo': +tests/qapi-schema/doc-bad-symbol.json:6: documentation comment is for 'food' diff --git a/tests/qapi-schema/doc-bad-union-member.err b/tests/qapi-schema/doc-bad-union-member.err index 4b016df7ff..da3cd806e3 100644 --- a/tests/qapi-schema/doc-bad-union-member.err +++ b/tests/qapi-schema/doc-bad-union-member.err @@ -1 +1 @@ -tests/qapi-schema/doc-bad-union-member.json:3: The following documented members are not in the declaration: a, b +tests/qapi-schema/doc-bad-union-member.json:3: the following documented members are not in the declaration: a, b diff --git a/tests/qapi-schema/doc-before-include.err b/tests/qapi-schema/doc-before-include.err index a649d38a63..e5566f11e9 100644 --- a/tests/qapi-schema/doc-before-include.err +++ b/tests/qapi-schema/doc-before-include.err @@ -1 +1 @@ -tests/qapi-schema/doc-before-include.json:3: Documentation for 'foo' is not followed by the definition +tests/qapi-schema/doc-before-include.json:3: documentation for 'foo' is not followed by the definition diff --git a/tests/qapi-schema/doc-before-pragma.err b/tests/qapi-schema/doc-before-pragma.err index c0fb0660d1..8a97ebb578 100644 --- a/tests/qapi-schema/doc-before-pragma.err +++ b/tests/qapi-schema/doc-before-pragma.err @@ -1 +1 @@ -tests/qapi-schema/doc-before-pragma.json:3: Documentation for 'foo' is not followed by the definition +tests/qapi-schema/doc-before-pragma.json:3: documentation for 'foo' is not followed by the definition diff --git a/tests/qapi-schema/doc-duplicated-return.err b/tests/qapi-schema/doc-duplicated-return.err index e48039f8e5..7631933093 100644 --- a/tests/qapi-schema/doc-duplicated-return.err +++ b/tests/qapi-schema/doc-duplicated-return.err @@ -1 +1 @@ -tests/qapi-schema/doc-duplicated-return.json:7:1: Duplicated 'Returns' section +tests/qapi-schema/doc-duplicated-return.json:7:1: duplicated 'Returns' section diff --git a/tests/qapi-schema/doc-duplicated-since.err b/tests/qapi-schema/doc-duplicated-since.err index 3fb890744a..5ee15ae2a1 100644 --- a/tests/qapi-schema/doc-duplicated-since.err +++ b/tests/qapi-schema/doc-duplicated-since.err @@ -1 +1 @@ -tests/qapi-schema/doc-duplicated-since.json:7:1: Duplicated 'Since' section +tests/qapi-schema/doc-duplicated-since.json:7:1: duplicated 'Since' section diff --git a/tests/qapi-schema/doc-empty-arg.err b/tests/qapi-schema/doc-empty-arg.err index 2895518fa7..3c78a37ae1 100644 --- a/tests/qapi-schema/doc-empty-arg.err +++ b/tests/qapi-schema/doc-empty-arg.err @@ -1 +1 @@ -tests/qapi-schema/doc-empty-arg.json:5:1: Invalid parameter name +tests/qapi-schema/doc-empty-arg.json:5:1: invalid parameter name diff --git a/tests/qapi-schema/doc-empty-section.err b/tests/qapi-schema/doc-empty-section.err index b61e4a7886..f6586c566f 100644 --- a/tests/qapi-schema/doc-empty-section.err +++ b/tests/qapi-schema/doc-empty-section.err @@ -1 +1 @@ -tests/qapi-schema/doc-empty-section.json:7:1: Empty doc section 'Note' +tests/qapi-schema/doc-empty-section.json:7:1: empty doc section 'Note' diff --git a/tests/qapi-schema/doc-empty-symbol.err b/tests/qapi-schema/doc-empty-symbol.err index 1936ad094f..2dcddca7f6 100644 --- a/tests/qapi-schema/doc-empty-symbol.err +++ b/tests/qapi-schema/doc-empty-symbol.err @@ -1 +1 @@ -tests/qapi-schema/doc-empty-symbol.json:4:1: Invalid name +tests/qapi-schema/doc-empty-symbol.json:4:1: invalid name diff --git a/tests/qapi-schema/doc-invalid-end.err b/tests/qapi-schema/doc-invalid-end.err index 2bda28cb54..6345aa6a0f 100644 --- a/tests/qapi-schema/doc-invalid-end.err +++ b/tests/qapi-schema/doc-invalid-end.err @@ -1 +1 @@ -tests/qapi-schema/doc-invalid-end.json:5:2: Documentation comment must end with '##' +tests/qapi-schema/doc-invalid-end.json:5:2: documentation comment must end with '##' diff --git a/tests/qapi-schema/doc-invalid-end2.err b/tests/qapi-schema/doc-invalid-end2.err index 6fad9c789e..13ead36fd2 100644 --- a/tests/qapi-schema/doc-invalid-end2.err +++ b/tests/qapi-schema/doc-invalid-end2.err @@ -1 +1 @@ -tests/qapi-schema/doc-invalid-end2.json:5:1: Junk after '##' at end of documentation comment +tests/qapi-schema/doc-invalid-end2.json:5:1: junk after '##' at end of documentation comment diff --git a/tests/qapi-schema/doc-invalid-start.err b/tests/qapi-schema/doc-invalid-start.err index 149af2bfac..dcaa9699d6 100644 --- a/tests/qapi-schema/doc-invalid-start.err +++ b/tests/qapi-schema/doc-invalid-start.err @@ -1 +1 @@ -tests/qapi-schema/doc-invalid-start.json:3:1: Junk after '##' at start of documentation comment +tests/qapi-schema/doc-invalid-start.json:3:1: junk after '##' at start of documentation comment diff --git a/tests/qapi-schema/doc-missing-colon.err b/tests/qapi-schema/doc-missing-colon.err index 817398b8e4..6fb5a380bd 100644 --- a/tests/qapi-schema/doc-missing-colon.err +++ b/tests/qapi-schema/doc-missing-colon.err @@ -1 +1 @@ -tests/qapi-schema/doc-missing-colon.json:4:1: Line should end with : +tests/qapi-schema/doc-missing-colon.json:4:1: line should end with ':' diff --git a/tests/qapi-schema/doc-missing-expr.err b/tests/qapi-schema/doc-missing-expr.err index c909e26eca..622a37cc6c 100644 --- a/tests/qapi-schema/doc-missing-expr.err +++ b/tests/qapi-schema/doc-missing-expr.err @@ -1 +1 @@ -tests/qapi-schema/doc-missing-expr.json:3: Documentation for 'bar' is not followed by the definition +tests/qapi-schema/doc-missing-expr.json:3: documentation for 'bar' is not followed by the definition diff --git a/tests/qapi-schema/doc-missing-space.err b/tests/qapi-schema/doc-missing-space.err index d6b46ffd77..1187ba12c4 100644 --- a/tests/qapi-schema/doc-missing-space.err +++ b/tests/qapi-schema/doc-missing-space.err @@ -1 +1 @@ -tests/qapi-schema/doc-missing-space.json:5:1: Missing space after # +tests/qapi-schema/doc-missing-space.json:5:1: missing space after # diff --git a/tests/qapi-schema/doc-missing.err b/tests/qapi-schema/doc-missing.err index 7f2f326b30..7fbf54ff65 100644 --- a/tests/qapi-schema/doc-missing.err +++ b/tests/qapi-schema/doc-missing.err @@ -1 +1,2 @@ -tests/qapi-schema/doc-missing.json:5: Expression missing documentation comment +tests/qapi-schema/doc-missing.json: In command 'undocumented': +tests/qapi-schema/doc-missing.json:5: documentation comment required diff --git a/tests/qapi-schema/doc-no-symbol.err b/tests/qapi-schema/doc-no-symbol.err index 75f032a942..9a3057730c 100644 --- a/tests/qapi-schema/doc-no-symbol.err +++ b/tests/qapi-schema/doc-no-symbol.err @@ -1 +1 @@ -tests/qapi-schema/doc-no-symbol.json:3: Expression documentation required +tests/qapi-schema/doc-no-symbol.json:3: definition documentation required diff --git a/tests/qapi-schema/double-data.err b/tests/qapi-schema/double-data.err deleted file mode 100644 index cc765c4ff2..0000000000 --- a/tests/qapi-schema/double-data.err +++ /dev/null @@ -1 +0,0 @@ -tests/qapi-schema/double-data.json:2:41: Duplicate key "data" diff --git a/tests/qapi-schema/double-data.json b/tests/qapi-schema/double-data.json deleted file mode 100644 index e76b519538..0000000000 --- a/tests/qapi-schema/double-data.json +++ /dev/null @@ -1,2 +0,0 @@ -# we reject an expression with duplicate top-level keys -{ 'struct': 'bar', 'data': { }, 'data': { 'string': 'str'} } diff --git a/tests/qapi-schema/double-type.err b/tests/qapi-schema/double-type.err index 69457173a7..23f88aae99 100644 --- a/tests/qapi-schema/double-type.err +++ b/tests/qapi-schema/double-type.err @@ -1,2 +1,3 @@ -tests/qapi-schema/double-type.json:2: Unknown key 'command' in struct 'bar' +tests/qapi-schema/double-type.json: In struct 'bar': +tests/qapi-schema/double-type.json:2: struct has unknown key 'command' Valid keys are 'base', 'data', 'features', 'if', 'struct'. diff --git a/tests/qapi-schema/duplicate-key.err b/tests/qapi-schema/duplicate-key.err index 6d02f83538..7f34a34eb6 100644 --- a/tests/qapi-schema/duplicate-key.err +++ b/tests/qapi-schema/duplicate-key.err @@ -1 +1 @@ -tests/qapi-schema/duplicate-key.json:3:10: Duplicate key "key" +tests/qapi-schema/duplicate-key.json:3:10: duplicate key 'key' diff --git a/tests/qapi-schema/duplicate-key.json b/tests/qapi-schema/duplicate-key.json index 14ac0e8a40..06b55840c9 100644 --- a/tests/qapi-schema/duplicate-key.json +++ b/tests/qapi-schema/duplicate-key.json @@ -1,3 +1,3 @@ -# QAPI cannot include the same key more than once in any {} +# Cannot include the same key more than once in any {} { 'key': 'value', 'key': 'value' } diff --git a/tests/qapi-schema/enum-bad-member.err b/tests/qapi-schema/enum-bad-member.err index 211db9e6fc..2b1b4f98d0 100644 --- a/tests/qapi-schema/enum-bad-member.err +++ b/tests/qapi-schema/enum-bad-member.err @@ -1 +1,2 @@ -tests/qapi-schema/enum-bad-member.json:2: Member of enum 'MyEnum' requires a string name +tests/qapi-schema/enum-bad-member.json: In enum 'MyEnum': +tests/qapi-schema/enum-bad-member.json:2: 'data' member requires a string name diff --git a/tests/qapi-schema/enum-bad-name.err b/tests/qapi-schema/enum-bad-name.err index 9c3c1002b7..3273a9808a 100644 --- a/tests/qapi-schema/enum-bad-name.err +++ b/tests/qapi-schema/enum-bad-name.err @@ -1 +1,2 @@ -tests/qapi-schema/enum-bad-name.json:2: Member of enum 'MyEnum' uses invalid name 'not^possible' +tests/qapi-schema/enum-bad-name.json: In enum 'MyEnum': +tests/qapi-schema/enum-bad-name.json:3: 'data' member 'not\possible' has an invalid name diff --git a/tests/qapi-schema/enum-bad-name.json b/tests/qapi-schema/enum-bad-name.json index 8506562b31..1c4620edda 100644 --- a/tests/qapi-schema/enum-bad-name.json +++ b/tests/qapi-schema/enum-bad-name.json @@ -1,2 +1,3 @@ # we ensure all enum names can map to C -{ 'enum': 'MyEnum', 'data': [ 'not^possible' ] } +# FIXME reports 'not\possible' instead of 'not\\possible' +{ 'enum': 'MyEnum', 'data': [ 'not\\possible' ] } diff --git a/tests/qapi-schema/enum-bad-prefix.err b/tests/qapi-schema/enum-bad-prefix.err index 399f5f7af5..933e33aa18 100644 --- a/tests/qapi-schema/enum-bad-prefix.err +++ b/tests/qapi-schema/enum-bad-prefix.err @@ -1 +1,2 @@ -tests/qapi-schema/enum-bad-prefix.json:2: Enum 'MyEnum' requires a string for 'prefix' +tests/qapi-schema/enum-bad-prefix.json: In enum 'MyEnum': +tests/qapi-schema/enum-bad-prefix.json:2: 'prefix' must be a string diff --git a/tests/qapi-schema/enum-clash-member.err b/tests/qapi-schema/enum-clash-member.err index 5403c78507..84e02db82c 100644 --- a/tests/qapi-schema/enum-clash-member.err +++ b/tests/qapi-schema/enum-clash-member.err @@ -1 +1,2 @@ -tests/qapi-schema/enum-clash-member.json:2: 'one_two' (member of MyEnum) collides with 'one-two' (member of MyEnum) +tests/qapi-schema/enum-clash-member.json: In enum 'MyEnum': +tests/qapi-schema/enum-clash-member.json:2: value 'one_two' collides with value 'one-two' diff --git a/tests/qapi-schema/enum-dict-member-unknown.err b/tests/qapi-schema/enum-dict-member-unknown.err index 2aae618be0..5df0236343 100644 --- a/tests/qapi-schema/enum-dict-member-unknown.err +++ b/tests/qapi-schema/enum-dict-member-unknown.err @@ -1,2 +1,3 @@ -tests/qapi-schema/enum-dict-member-unknown.json:2: Unknown key 'bad-key' in dictionary member of enum 'MyEnum' +tests/qapi-schema/enum-dict-member-unknown.json: In enum 'MyEnum': +tests/qapi-schema/enum-dict-member-unknown.json:2: 'data' member has unknown key 'bad-key' Valid keys are 'if', 'name'. diff --git a/tests/qapi-schema/enum-if-invalid.err b/tests/qapi-schema/enum-if-invalid.err index 54c3cf887b..30c1f0e91c 100644 --- a/tests/qapi-schema/enum-if-invalid.err +++ b/tests/qapi-schema/enum-if-invalid.err @@ -1 +1,2 @@ -tests/qapi-schema/enum-if-invalid.json:2: 'if' condition must be a string or a list of strings +tests/qapi-schema/enum-if-invalid.json: In enum 'TestIfEnum': +tests/qapi-schema/enum-if-invalid.json:2: 'if' condition of 'data' member 'bar' must be a string or a list of strings diff --git a/tests/qapi-schema/enum-int-member.err b/tests/qapi-schema/enum-int-member.err index 071c5213d8..27f06e334c 100644 --- a/tests/qapi-schema/enum-int-member.err +++ b/tests/qapi-schema/enum-int-member.err @@ -1 +1 @@ -tests/qapi-schema/enum-int-member.json:3:31: Stray "1" +tests/qapi-schema/enum-int-member.json:3:31: stray '1' diff --git a/tests/qapi-schema/enum-member-case.err b/tests/qapi-schema/enum-member-case.err index 3c67a3a067..e6b080c6e5 100644 --- a/tests/qapi-schema/enum-member-case.err +++ b/tests/qapi-schema/enum-member-case.err @@ -1 +1,2 @@ -tests/qapi-schema/enum-member-case.json:4: 'Value' (member of NoWayThisWillGetWhitelisted) should not use uppercase +tests/qapi-schema/enum-member-case.json: In enum 'NoWayThisWillGetWhitelisted': +tests/qapi-schema/enum-member-case.json:4: 'data' member 'Value' uses uppercase in name diff --git a/tests/qapi-schema/enum-missing-data.err b/tests/qapi-schema/enum-missing-data.err index ba4873ae69..4809b01f34 100644 --- a/tests/qapi-schema/enum-missing-data.err +++ b/tests/qapi-schema/enum-missing-data.err @@ -1 +1,2 @@ -tests/qapi-schema/enum-missing-data.json:2: Key 'data' is missing from enum 'MyEnum' +tests/qapi-schema/enum-missing-data.json: In enum 'MyEnum': +tests/qapi-schema/enum-missing-data.json:2: enum misses key 'data' diff --git a/tests/qapi-schema/enum-wrong-data.err b/tests/qapi-schema/enum-wrong-data.err index 11b43471cf..ad5f0ce46f 100644 --- a/tests/qapi-schema/enum-wrong-data.err +++ b/tests/qapi-schema/enum-wrong-data.err @@ -1 +1,2 @@ -tests/qapi-schema/enum-wrong-data.json:2: Enum 'MyEnum' requires an array for 'data' +tests/qapi-schema/enum-wrong-data.json: In enum 'MyEnum': +tests/qapi-schema/enum-wrong-data.json:2: 'data' must be an array diff --git a/tests/qapi-schema/escape-outside-string.err b/tests/qapi-schema/escape-outside-string.err index b9b8837fd2..06f5f2ed55 100644 --- a/tests/qapi-schema/escape-outside-string.err +++ b/tests/qapi-schema/escape-outside-string.err @@ -1 +1 @@ -tests/qapi-schema/escape-outside-string.json:3:27: Stray "\" +tests/qapi-schema/escape-outside-string.json:3:27: stray '\' diff --git a/tests/qapi-schema/escape-outside-string.json b/tests/qapi-schema/escape-outside-string.json deleted file mode 100644 index 482f79554b..0000000000 --- a/tests/qapi-schema/escape-outside-string.json +++ /dev/null @@ -1,3 +0,0 @@ -# escape sequences are permitted only inside strings -# { 'command': 'foo', 'data': {} } -{ 'command': 'foo', 'data'\u003a{} } diff --git a/tests/qapi-schema/escape-too-big.err b/tests/qapi-schema/escape-too-big.err deleted file mode 100644 index d9aeb5dc38..0000000000 --- a/tests/qapi-schema/escape-too-big.err +++ /dev/null @@ -1 +0,0 @@ -tests/qapi-schema/escape-too-big.json:3:14: For now, \u escape only supports non-zero values up to \u007f diff --git a/tests/qapi-schema/escape-too-big.json b/tests/qapi-schema/escape-too-big.json deleted file mode 100644 index 62bcecd557..0000000000 --- a/tests/qapi-schema/escape-too-big.json +++ /dev/null @@ -1,3 +0,0 @@ -# we don't support full Unicode strings, yet -# { 'command': 'Ă©' } -{ 'command': '\u00e9' } diff --git a/tests/qapi-schema/escape-too-short.err b/tests/qapi-schema/escape-too-short.err deleted file mode 100644 index 934de598ee..0000000000 --- a/tests/qapi-schema/escape-too-short.err +++ /dev/null @@ -1 +0,0 @@ -tests/qapi-schema/escape-too-short.json:3:14: \u escape needs 4 hex digits diff --git a/tests/qapi-schema/escape-too-short.json b/tests/qapi-schema/escape-too-short.json deleted file mode 100644 index 6cb1dec8f7..0000000000 --- a/tests/qapi-schema/escape-too-short.json +++ /dev/null @@ -1,3 +0,0 @@ -# the \u escape requires 4 hex digits -# { 'command': 'a' } -{ 'command': '\u61' } diff --git a/tests/qapi-schema/event-boxed-empty.err b/tests/qapi-schema/event-boxed-empty.err index 68ec6f2d2b..931c10b036 100644 --- a/tests/qapi-schema/event-boxed-empty.err +++ b/tests/qapi-schema/event-boxed-empty.err @@ -1 +1,2 @@ -tests/qapi-schema/event-boxed-empty.json:2: Use of 'boxed' requires 'data' +tests/qapi-schema/event-boxed-empty.json: In event 'FOO': +tests/qapi-schema/event-boxed-empty.json:2: 'boxed': true requires 'data' diff --git a/tests/qapi-schema/event-member-invalid-dict.err b/tests/qapi-schema/event-member-invalid-dict.err index 1a57fa29b0..8406c43df7 100644 --- a/tests/qapi-schema/event-member-invalid-dict.err +++ b/tests/qapi-schema/event-member-invalid-dict.err @@ -1 +1,2 @@ -tests/qapi-schema/event-member-invalid-dict.json:1: Key 'type' is missing from member 'a' of 'data' for event 'EVENT_A' +tests/qapi-schema/event-member-invalid-dict.json: In event 'EVENT_A': +tests/qapi-schema/event-member-invalid-dict.json:1: 'data' member 'a' misses key 'type' diff --git a/tests/qapi-schema/event-nest-struct.err b/tests/qapi-schema/event-nest-struct.err index 5a42701b8f..1a3254a73c 100644 --- a/tests/qapi-schema/event-nest-struct.err +++ b/tests/qapi-schema/event-nest-struct.err @@ -1 +1,2 @@ -tests/qapi-schema/event-nest-struct.json:1: Member 'a' of 'data' for event 'EVENT_A' should be a type name +tests/qapi-schema/event-nest-struct.json: In event 'EVENT_A': +tests/qapi-schema/event-nest-struct.json:1: 'data' member 'a' should be a type name diff --git a/tests/qapi-schema/features-bad-type.err b/tests/qapi-schema/features-bad-type.err index 5fb95c2f90..30deb8b624 100644 --- a/tests/qapi-schema/features-bad-type.err +++ b/tests/qapi-schema/features-bad-type.err @@ -1 +1,2 @@ -tests/qapi-schema/features-bad-type.json:1: Feature of struct FeatureStruct0 requires a string name +tests/qapi-schema/features-bad-type.json: In struct 'FeatureStruct0': +tests/qapi-schema/features-bad-type.json:1: 'features' member requires a string name diff --git a/tests/qapi-schema/features-duplicate-name.err b/tests/qapi-schema/features-duplicate-name.err index c0a4cccae6..a99bbde737 100644 --- a/tests/qapi-schema/features-duplicate-name.err +++ b/tests/qapi-schema/features-duplicate-name.err @@ -1 +1,2 @@ -tests/qapi-schema/features-duplicate-name.json:1: 'foo' (feature of FeatureStruct0) collides with 'foo' (feature of FeatureStruct0) +tests/qapi-schema/features-duplicate-name.json: In struct 'FeatureStruct0': +tests/qapi-schema/features-duplicate-name.json:1: feature 'foo' collides with feature 'foo' diff --git a/tests/qapi-schema/features-if-invalid.err b/tests/qapi-schema/features-if-invalid.err new file mode 100644 index 0000000000..ffb39378af --- /dev/null +++ b/tests/qapi-schema/features-if-invalid.err @@ -0,0 +1,2 @@ +tests/qapi-schema/features-if-invalid.json: In struct 'Stru': +tests/qapi-schema/features-if-invalid.json:2: 'if' condition of 'features' member 'f' must be a string or a list of strings diff --git a/tests/qapi-schema/double-data.exit b/tests/qapi-schema/features-if-invalid.exit index d00491fd7e..d00491fd7e 100644 --- a/tests/qapi-schema/double-data.exit +++ b/tests/qapi-schema/features-if-invalid.exit diff --git a/tests/qapi-schema/features-if-invalid.json b/tests/qapi-schema/features-if-invalid.json new file mode 100644 index 0000000000..89c2a6c234 --- /dev/null +++ b/tests/qapi-schema/features-if-invalid.json @@ -0,0 +1,4 @@ +# Cover feature with invalid 'if' +{ 'struct': 'Stru', + 'data': {}, + 'features': [{'name': 'f', 'if': false }] } diff --git a/tests/qapi-schema/double-data.out b/tests/qapi-schema/features-if-invalid.out index e69de29bb2..e69de29bb2 100644 --- a/tests/qapi-schema/double-data.out +++ b/tests/qapi-schema/features-if-invalid.out diff --git a/tests/qapi-schema/features-missing-name.err b/tests/qapi-schema/features-missing-name.err index 4f1d2715aa..b8db328acc 100644 --- a/tests/qapi-schema/features-missing-name.err +++ b/tests/qapi-schema/features-missing-name.err @@ -1 +1,2 @@ -tests/qapi-schema/features-missing-name.json:1: Key 'name' is missing from feature of struct FeatureStruct0 +tests/qapi-schema/features-missing-name.json: In struct 'FeatureStruct0': +tests/qapi-schema/features-missing-name.json:1: 'features' member misses key 'name' diff --git a/tests/qapi-schema/features-name-bad-type.err b/tests/qapi-schema/features-name-bad-type.err index 8a3eecb972..86db2c0ea2 100644 --- a/tests/qapi-schema/features-name-bad-type.err +++ b/tests/qapi-schema/features-name-bad-type.err @@ -1 +1,2 @@ -tests/qapi-schema/features-name-bad-type.json:1: Feature of struct FeatureStruct0 requires a string name +tests/qapi-schema/features-name-bad-type.json: In struct 'FeatureStruct0': +tests/qapi-schema/features-name-bad-type.json:1: 'features' member requires a string name diff --git a/tests/qapi-schema/features-no-list.err b/tests/qapi-schema/features-no-list.err index 61ed68612b..e493f85057 100644 --- a/tests/qapi-schema/features-no-list.err +++ b/tests/qapi-schema/features-no-list.err @@ -1 +1,2 @@ -tests/qapi-schema/features-no-list.json:1: Struct 'FeatureStruct0' requires an array for 'features' +tests/qapi-schema/features-no-list.json: In struct 'FeatureStruct0': +tests/qapi-schema/features-no-list.json:1: 'features' must be an array diff --git a/tests/qapi-schema/features-unknown-key.err b/tests/qapi-schema/features-unknown-key.err index a1d693030d..22f5dcf4b0 100644 --- a/tests/qapi-schema/features-unknown-key.err +++ b/tests/qapi-schema/features-unknown-key.err @@ -1,2 +1,3 @@ -tests/qapi-schema/features-unknown-key.json:1: Unknown key 'colour' in feature of struct FeatureStruct0 +tests/qapi-schema/features-unknown-key.json: In struct 'FeatureStruct0': +tests/qapi-schema/features-unknown-key.json:1: 'features' member has unknown key 'colour' Valid keys are 'if', 'name'. diff --git a/tests/qapi-schema/flat-union-array-branch.err b/tests/qapi-schema/flat-union-array-branch.err index 8ea91eadb2..de07a7b32a 100644 --- a/tests/qapi-schema/flat-union-array-branch.err +++ b/tests/qapi-schema/flat-union-array-branch.err @@ -1 +1,2 @@ -tests/qapi-schema/flat-union-array-branch.json:8: Member 'value1' of union 'TestUnion' cannot be an array +tests/qapi-schema/flat-union-array-branch.json: In union 'TestUnion': +tests/qapi-schema/flat-union-array-branch.json:8: 'data' member 'value1' cannot be an array diff --git a/tests/qapi-schema/flat-union-bad-base.err b/tests/qapi-schema/flat-union-bad-base.err index bee24a217a..5da7602c20 100644 --- a/tests/qapi-schema/flat-union-bad-base.err +++ b/tests/qapi-schema/flat-union-bad-base.err @@ -1 +1,2 @@ -tests/qapi-schema/flat-union-bad-base.json:8: 'string' (member of TestTypeA) collides with 'string' (base of TestUnion) +tests/qapi-schema/flat-union-bad-base.json: In union 'TestUnion': +tests/qapi-schema/flat-union-bad-base.json:8: member 'string' of type 'TestTypeA' collides with base member 'string' diff --git a/tests/qapi-schema/flat-union-bad-discriminator.err b/tests/qapi-schema/flat-union-bad-discriminator.err index c38cc8e4df..c1b4209ffd 100644 --- a/tests/qapi-schema/flat-union-bad-discriminator.err +++ b/tests/qapi-schema/flat-union-bad-discriminator.err @@ -1 +1,2 @@ -tests/qapi-schema/flat-union-bad-discriminator.json:11: Discriminator of flat union 'TestUnion' requires a string name +tests/qapi-schema/flat-union-bad-discriminator.json: In union 'TestUnion': +tests/qapi-schema/flat-union-bad-discriminator.json:11: 'discriminator' requires a string name diff --git a/tests/qapi-schema/flat-union-base-any.err b/tests/qapi-schema/flat-union-base-any.err index 646f1c9cd1..7ab3402396 100644 --- a/tests/qapi-schema/flat-union-base-any.err +++ b/tests/qapi-schema/flat-union-base-any.err @@ -1 +1,2 @@ -tests/qapi-schema/flat-union-base-any.json:8: 'base' for union 'TestUnion' cannot use built-in type 'any' +tests/qapi-schema/flat-union-base-any.json: In union 'TestUnion': +tests/qapi-schema/flat-union-base-any.json:8: 'base' requires a struct type, built-in type 'any' isn't diff --git a/tests/qapi-schema/flat-union-base-union.err b/tests/qapi-schema/flat-union-base-union.err index f138395e45..5db7b1e404 100644 --- a/tests/qapi-schema/flat-union-base-union.err +++ b/tests/qapi-schema/flat-union-base-union.err @@ -1 +1,2 @@ -tests/qapi-schema/flat-union-base-union.json:14: 'base' for union 'TestUnion' cannot use union type 'UnionBase' +tests/qapi-schema/flat-union-base-union.json: In union 'TestUnion': +tests/qapi-schema/flat-union-base-union.json:14: 'base' requires a struct type, union type 'UnionBase' isn't diff --git a/tests/qapi-schema/flat-union-clash-member.err b/tests/qapi-schema/flat-union-clash-member.err index 2adf69755a..40f10681f8 100644 --- a/tests/qapi-schema/flat-union-clash-member.err +++ b/tests/qapi-schema/flat-union-clash-member.err @@ -1 +1,2 @@ -tests/qapi-schema/flat-union-clash-member.json:11: 'name' (member of Branch1) collides with 'name' (member of Base) +tests/qapi-schema/flat-union-clash-member.json: In union 'TestUnion': +tests/qapi-schema/flat-union-clash-member.json:11: member 'name' of type 'Branch1' collides with member 'name' of type 'Base' diff --git a/tests/qapi-schema/flat-union-discriminator-bad-name.err b/tests/qapi-schema/flat-union-discriminator-bad-name.err new file mode 100644 index 0000000000..2a0deb6a0e --- /dev/null +++ b/tests/qapi-schema/flat-union-discriminator-bad-name.err @@ -0,0 +1,2 @@ +tests/qapi-schema/flat-union-discriminator-bad-name.json: In union 'MyUnion': +tests/qapi-schema/flat-union-discriminator-bad-name.json:6: discriminator '*switch' is not a member of 'base' diff --git a/tests/qapi-schema/escape-outside-string.exit b/tests/qapi-schema/flat-union-discriminator-bad-name.exit index d00491fd7e..d00491fd7e 100644 --- a/tests/qapi-schema/escape-outside-string.exit +++ b/tests/qapi-schema/flat-union-discriminator-bad-name.exit diff --git a/tests/qapi-schema/flat-union-discriminator-bad-name.json b/tests/qapi-schema/flat-union-discriminator-bad-name.json new file mode 100644 index 0000000000..3ae8c06a89 --- /dev/null +++ b/tests/qapi-schema/flat-union-discriminator-bad-name.json @@ -0,0 +1,10 @@ +# discriminator '*switch' isn't a member of base, 'switch' is +{ 'enum': 'Enum', 'data': [ 'one', 'two' ] } +{ 'struct': 'Base', + 'data': { '*switch': 'Enum' } } +{ 'struct': 'Branch', 'data': { 'name': 'str' } } +{ 'union': 'MyUnion', + 'base': 'Base', + 'discriminator': '*switch', + 'data': { 'one': 'Branch', + 'two': 'Branch' } } diff --git a/tests/qapi-schema/escape-outside-string.out b/tests/qapi-schema/flat-union-discriminator-bad-name.out index e69de29bb2..e69de29bb2 100644 --- a/tests/qapi-schema/escape-outside-string.out +++ b/tests/qapi-schema/flat-union-discriminator-bad-name.out diff --git a/tests/qapi-schema/flat-union-empty.err b/tests/qapi-schema/flat-union-empty.err index 15754f54eb..91a5b57f5d 100644 --- a/tests/qapi-schema/flat-union-empty.err +++ b/tests/qapi-schema/flat-union-empty.err @@ -1 +1,2 @@ -tests/qapi-schema/flat-union-empty.json:4: Union 'Union' cannot have empty 'data' +tests/qapi-schema/flat-union-empty.json: In union 'Union': +tests/qapi-schema/flat-union-empty.json:4: union has no branches diff --git a/tests/qapi-schema/flat-union-empty.json b/tests/qapi-schema/flat-union-empty.json index 77f1d9abfb..83e1cc7b96 100644 --- a/tests/qapi-schema/flat-union-empty.json +++ b/tests/qapi-schema/flat-union-empty.json @@ -1,4 +1,4 @@ -# flat unions cannot be empty +# flat union discriminator cannot be empty { 'enum': 'Empty', 'data': [ ] } { 'struct': 'Base', 'data': { 'type': 'Empty' } } { 'union': 'Union', 'base': 'Base', 'discriminator': 'type', 'data': { } } diff --git a/tests/qapi-schema/flat-union-inline-invalid-dict.err b/tests/qapi-schema/flat-union-inline-invalid-dict.err index 9c4c45b7f0..d353bdd338 100644 --- a/tests/qapi-schema/flat-union-inline-invalid-dict.err +++ b/tests/qapi-schema/flat-union-inline-invalid-dict.err @@ -1 +1,2 @@ -tests/qapi-schema/flat-union-inline-invalid-dict.json:7: Key 'type' is missing from member 'value1' of union 'TestUnion' +tests/qapi-schema/flat-union-inline-invalid-dict.json: In union 'TestUnion': +tests/qapi-schema/flat-union-inline-invalid-dict.json:7: 'data' member 'value1' misses key 'type' diff --git a/tests/qapi-schema/flat-union-inline.err b/tests/qapi-schema/flat-union-inline.err index 2333358d28..95b1e8c1b7 100644 --- a/tests/qapi-schema/flat-union-inline.err +++ b/tests/qapi-schema/flat-union-inline.err @@ -1 +1,2 @@ -tests/qapi-schema/flat-union-inline.json:7: Member 'value1' of union 'TestUnion' should be a type name +tests/qapi-schema/flat-union-inline.json: In union 'TestUnion': +tests/qapi-schema/flat-union-inline.json:7: 'data' member 'value1' should be a type name diff --git a/tests/qapi-schema/flat-union-int-branch.err b/tests/qapi-schema/flat-union-int-branch.err index faf01573b7..416b696c8f 100644 --- a/tests/qapi-schema/flat-union-int-branch.err +++ b/tests/qapi-schema/flat-union-int-branch.err @@ -1 +1,2 @@ -tests/qapi-schema/flat-union-int-branch.json:8: Member 'value1' of union 'TestUnion' cannot use built-in type 'int' +tests/qapi-schema/flat-union-int-branch.json: In union 'TestUnion': +tests/qapi-schema/flat-union-int-branch.json:8: branch 'value1' cannot use built-in type 'int' diff --git a/tests/qapi-schema/flat-union-invalid-branch-key.err b/tests/qapi-schema/flat-union-invalid-branch-key.err index ccf72d2dfe..6997b3387d 100644 --- a/tests/qapi-schema/flat-union-invalid-branch-key.err +++ b/tests/qapi-schema/flat-union-invalid-branch-key.err @@ -1 +1,2 @@ -tests/qapi-schema/flat-union-invalid-branch-key.json:13: Discriminator value 'value_wrong' is not found in enum 'TestEnum' +tests/qapi-schema/flat-union-invalid-branch-key.json: In union 'TestUnion': +tests/qapi-schema/flat-union-invalid-branch-key.json:13: branch 'value_wrong' is not a value of enum type 'TestEnum' diff --git a/tests/qapi-schema/flat-union-invalid-discriminator.err b/tests/qapi-schema/flat-union-invalid-discriminator.err index 5f4055614e..3f80de3044 100644 --- a/tests/qapi-schema/flat-union-invalid-discriminator.err +++ b/tests/qapi-schema/flat-union-invalid-discriminator.err @@ -1 +1,2 @@ -tests/qapi-schema/flat-union-invalid-discriminator.json:13: Discriminator 'enum_wrong' is not a member of base struct 'TestBase' +tests/qapi-schema/flat-union-invalid-discriminator.json: In union 'TestUnion': +tests/qapi-schema/flat-union-invalid-discriminator.json:10: discriminator 'enum_wrong' is not a member of 'base' diff --git a/tests/qapi-schema/flat-union-invalid-discriminator.json b/tests/qapi-schema/flat-union-invalid-discriminator.json index 48b94c3a4d..c4fce97362 100644 --- a/tests/qapi-schema/flat-union-invalid-discriminator.json +++ b/tests/qapi-schema/flat-union-invalid-discriminator.json @@ -1,9 +1,6 @@ { 'enum': 'TestEnum', 'data': [ 'value1', 'value2' ] } -{ 'struct': 'TestBase', - 'data': { 'enum1': 'TestEnum' } } - { 'struct': 'TestTypeA', 'data': { 'string': 'str' } } @@ -11,7 +8,7 @@ 'data': { 'integer': 'int' } } { 'union': 'TestUnion', - 'base': 'TestBase', + 'base': { 'enum1': 'TestEnum' }, 'discriminator': 'enum_wrong', 'data': { 'value1': 'TestTypeA', 'value2': 'TestTypeB' } } diff --git a/tests/qapi-schema/flat-union-invalid-if-discriminator.err b/tests/qapi-schema/flat-union-invalid-if-discriminator.err index 0c94c9860d..d2b35be9ae 100644 --- a/tests/qapi-schema/flat-union-invalid-if-discriminator.err +++ b/tests/qapi-schema/flat-union-invalid-if-discriminator.err @@ -1 +1,2 @@ -tests/qapi-schema/flat-union-invalid-if-discriminator.json:13: The discriminator TestBase.enum1 for union TestUnion must not be conditional +tests/qapi-schema/flat-union-invalid-if-discriminator.json: In union 'TestUnion': +tests/qapi-schema/flat-union-invalid-if-discriminator.json:10: discriminator member 'enum1' of 'base' must not be conditional diff --git a/tests/qapi-schema/flat-union-invalid-if-discriminator.json b/tests/qapi-schema/flat-union-invalid-if-discriminator.json index 618ec36396..e49992b798 100644 --- a/tests/qapi-schema/flat-union-invalid-if-discriminator.json +++ b/tests/qapi-schema/flat-union-invalid-if-discriminator.json @@ -1,9 +1,6 @@ { 'enum': 'TestEnum', 'data': [ 'value1', 'value2' ] } -{ 'struct': 'TestBase', - 'data': { 'enum1': { 'type': 'TestEnum', 'if': 'FOO' } } } - { 'struct': 'TestTypeA', 'data': { 'string': 'str' } } @@ -11,7 +8,7 @@ 'data': { 'integer': 'int' } } { 'union': 'TestUnion', - 'base': 'TestBase', + 'base': { 'enum1': { 'type': 'TestEnum', 'if': 'FOO' } }, 'discriminator': 'enum1', 'data': { 'value1': 'TestTypeA', 'value2': 'TestTypeB' } } diff --git a/tests/qapi-schema/flat-union-no-base.err b/tests/qapi-schema/flat-union-no-base.err index 841c93b554..a16f3231f1 100644 --- a/tests/qapi-schema/flat-union-no-base.err +++ b/tests/qapi-schema/flat-union-no-base.err @@ -1 +1,2 @@ -tests/qapi-schema/flat-union-no-base.json:9: Flat union 'TestUnion' must have a base +tests/qapi-schema/flat-union-no-base.json: In union 'TestUnion': +tests/qapi-schema/flat-union-no-base.json:9: 'discriminator' requires 'base' diff --git a/tests/qapi-schema/flat-union-optional-discriminator.err b/tests/qapi-schema/flat-union-optional-discriminator.err index aaabedb3bd..49fbf5b04d 100644 --- a/tests/qapi-schema/flat-union-optional-discriminator.err +++ b/tests/qapi-schema/flat-union-optional-discriminator.err @@ -1 +1,2 @@ -tests/qapi-schema/flat-union-optional-discriminator.json:6: Discriminator of flat union 'MyUnion' does not allow optional name '*switch' +tests/qapi-schema/flat-union-optional-discriminator.json: In union 'MyUnion': +tests/qapi-schema/flat-union-optional-discriminator.json:6: discriminator member 'switch' of base type 'Base' must not be optional diff --git a/tests/qapi-schema/flat-union-optional-discriminator.json b/tests/qapi-schema/flat-union-optional-discriminator.json index 08a8f7ef8b..2e7f766f60 100644 --- a/tests/qapi-schema/flat-union-optional-discriminator.json +++ b/tests/qapi-schema/flat-union-optional-discriminator.json @@ -5,6 +5,6 @@ { 'struct': 'Branch', 'data': { 'name': 'str' } } { 'union': 'MyUnion', 'base': 'Base', - 'discriminator': '*switch', + 'discriminator': 'switch', 'data': { 'one': 'Branch', 'two': 'Branch' } } diff --git a/tests/qapi-schema/flat-union-string-discriminator.err b/tests/qapi-schema/flat-union-string-discriminator.err index 200016bd5c..fb499188aa 100644 --- a/tests/qapi-schema/flat-union-string-discriminator.err +++ b/tests/qapi-schema/flat-union-string-discriminator.err @@ -1 +1,2 @@ -tests/qapi-schema/flat-union-string-discriminator.json:13: Discriminator 'kind' must be of enumeration type +tests/qapi-schema/flat-union-string-discriminator.json: In union 'TestUnion': +tests/qapi-schema/flat-union-string-discriminator.json:13: discriminator member 'kind' of base type 'TestBase' must be of enum type diff --git a/tests/qapi-schema/funny-char.err b/tests/qapi-schema/funny-char.err index bfc890cd9f..132fac93ea 100644 --- a/tests/qapi-schema/funny-char.err +++ b/tests/qapi-schema/funny-char.err @@ -1 +1 @@ -tests/qapi-schema/funny-char.json:2:36: Stray ";" +tests/qapi-schema/funny-char.json:2:36: stray ';' diff --git a/tests/qapi-schema/funny-word.err b/tests/qapi-schema/funny-word.err new file mode 100644 index 0000000000..d9286c8962 --- /dev/null +++ b/tests/qapi-schema/funny-word.err @@ -0,0 +1 @@ +tests/qapi-schema/funny-word.json:1:3: stray 'command' diff --git a/tests/qapi-schema/escape-too-big.exit b/tests/qapi-schema/funny-word.exit index d00491fd7e..d00491fd7e 100644 --- a/tests/qapi-schema/escape-too-big.exit +++ b/tests/qapi-schema/funny-word.exit diff --git a/tests/qapi-schema/funny-word.json b/tests/qapi-schema/funny-word.json new file mode 100644 index 0000000000..1153b9f12f --- /dev/null +++ b/tests/qapi-schema/funny-word.json @@ -0,0 +1 @@ +{ command: 'foo' } diff --git a/tests/qapi-schema/escape-too-big.out b/tests/qapi-schema/funny-word.out index e69de29bb2..e69de29bb2 100644 --- a/tests/qapi-schema/escape-too-big.out +++ b/tests/qapi-schema/funny-word.out diff --git a/tests/qapi-schema/ident-with-escape.err b/tests/qapi-schema/ident-with-escape.err index e69de29bb2..1117283c81 100644 --- a/tests/qapi-schema/ident-with-escape.err +++ b/tests/qapi-schema/ident-with-escape.err @@ -0,0 +1 @@ +tests/qapi-schema/ident-with-escape.json:3:3: unknown escape \u diff --git a/tests/qapi-schema/ident-with-escape.exit b/tests/qapi-schema/ident-with-escape.exit index 573541ac97..d00491fd7e 100644 --- a/tests/qapi-schema/ident-with-escape.exit +++ b/tests/qapi-schema/ident-with-escape.exit @@ -1 +1 @@ -0 +1 diff --git a/tests/qapi-schema/ident-with-escape.json b/tests/qapi-schema/ident-with-escape.json index 56617501e7..76b4503d95 100644 --- a/tests/qapi-schema/ident-with-escape.json +++ b/tests/qapi-schema/ident-with-escape.json @@ -1,4 +1,4 @@ -# we allow escape sequences in strings, if they map back to ASCII +# we don't recognize any \ escapes other than \\ (tested elsewhere) # { 'command': 'fooA', 'data': { 'bar1': 'str' } } { 'c\u006fmmand': '\u0066\u006f\u006FA', 'd\u0061ta': { '\u0062\u0061\u00721': '\u0073\u0074\u0072' } } diff --git a/tests/qapi-schema/ident-with-escape.out b/tests/qapi-schema/ident-with-escape.out index 39754eba8c..e69de29bb2 100644 --- a/tests/qapi-schema/ident-with-escape.out +++ b/tests/qapi-schema/ident-with-escape.out @@ -1,16 +0,0 @@ -module None -object q_empty -enum QType - prefix QTYPE - member none - member qnull - member qnum - member qstring - member qdict - member qlist - member qbool -module ident-with-escape.json -object q_obj_fooA-arg - member bar1: str optional=False -command fooA q_obj_fooA-arg -> None - gen=True success_response=True boxed=False oob=False preconfig=False diff --git a/tests/qapi-schema/include-before-err.err b/tests/qapi-schema/include-before-err.err index 55652751e1..098314bc49 100644 --- a/tests/qapi-schema/include-before-err.err +++ b/tests/qapi-schema/include-before-err.err @@ -1 +1 @@ -tests/qapi-schema/include-before-err.json:2:13: Expected ":" +tests/qapi-schema/include-before-err.json:2:13: expected ':' diff --git a/tests/qapi-schema/include-cycle.err b/tests/qapi-schema/include-cycle.err index bdcd07dce2..52028669b5 100644 --- a/tests/qapi-schema/include-cycle.err +++ b/tests/qapi-schema/include-cycle.err @@ -1,3 +1,3 @@ In file included from tests/qapi-schema/include-cycle.json:1: In file included from tests/qapi-schema/include-cycle-b.json:1: -tests/qapi-schema/include-cycle-c.json:1: Inclusion loop for include-cycle.json +tests/qapi-schema/include-cycle-c.json:1: inclusion loop for include-cycle.json diff --git a/tests/qapi-schema/include-extra-junk.err b/tests/qapi-schema/include-extra-junk.err index e6ef2a3720..854cec3ce3 100644 --- a/tests/qapi-schema/include-extra-junk.err +++ b/tests/qapi-schema/include-extra-junk.err @@ -1 +1 @@ -tests/qapi-schema/include-extra-junk.json:3: Invalid 'include' directive +tests/qapi-schema/include-extra-junk.json:3: invalid 'include' directive diff --git a/tests/qapi-schema/include-format-err.err b/tests/qapi-schema/include-format-err.err deleted file mode 100644 index 721ff4eccc..0000000000 --- a/tests/qapi-schema/include-format-err.err +++ /dev/null @@ -1 +0,0 @@ -tests/qapi-schema/include-format-err.json:1: Invalid 'include' directive diff --git a/tests/qapi-schema/include-format-err.json b/tests/qapi-schema/include-format-err.json deleted file mode 100644 index 44980f026f..0000000000 --- a/tests/qapi-schema/include-format-err.json +++ /dev/null @@ -1,2 +0,0 @@ -{ 'include': 'include-simple-sub.json', - 'foo': 'bar' } diff --git a/tests/qapi-schema/include-nested-err.err b/tests/qapi-schema/include-nested-err.err index 1b7b22706b..11928b4f7f 100644 --- a/tests/qapi-schema/include-nested-err.err +++ b/tests/qapi-schema/include-nested-err.err @@ -1,2 +1,2 @@ In file included from tests/qapi-schema/include-nested-err.json:1: -tests/qapi-schema/missing-colon.json:1:10: Expected ":" +tests/qapi-schema/missing-colon.json:1:10: expected ':' diff --git a/tests/qapi-schema/include-no-file.err b/tests/qapi-schema/include-no-file.err index e42bcf4bc1..0a6c6bb4a9 100644 --- a/tests/qapi-schema/include-no-file.err +++ b/tests/qapi-schema/include-no-file.err @@ -1 +1 @@ -tests/qapi-schema/include-no-file.json:1: No such file or directory: tests/qapi-schema/include-no-file-sub.json +tests/qapi-schema/include-no-file.json:1: can't read include file 'tests/qapi-schema/include-no-file-sub.json': No such file or directory diff --git a/tests/qapi-schema/include-non-file.err b/tests/qapi-schema/include-non-file.err index faae1eacf1..65dd3c7c2c 100644 --- a/tests/qapi-schema/include-non-file.err +++ b/tests/qapi-schema/include-non-file.err @@ -1 +1 @@ -tests/qapi-schema/include-non-file.json:1: Value of 'include' must be a string +tests/qapi-schema/include-non-file.json:1: value of 'include' must be a string diff --git a/tests/qapi-schema/include-self-cycle.err b/tests/qapi-schema/include-self-cycle.err index 981742ae5f..c84795d1dc 100644 --- a/tests/qapi-schema/include-self-cycle.err +++ b/tests/qapi-schema/include-self-cycle.err @@ -1 +1 @@ -tests/qapi-schema/include-self-cycle.json:1: Inclusion loop for include-self-cycle.json +tests/qapi-schema/include-self-cycle.json:1: inclusion loop for include-self-cycle.json diff --git a/tests/qapi-schema/leading-comma-list.err b/tests/qapi-schema/leading-comma-list.err index f5c870bb9c..cddf471f71 100644 --- a/tests/qapi-schema/leading-comma-list.err +++ b/tests/qapi-schema/leading-comma-list.err @@ -1 +1 @@ -tests/qapi-schema/leading-comma-list.json:2:13: Expected "{", "[", "]", string, boolean or "null" +tests/qapi-schema/leading-comma-list.json:2:13: expected '{', '[', ']', string, boolean or 'null' diff --git a/tests/qapi-schema/leading-comma-object.err b/tests/qapi-schema/leading-comma-object.err index f767b95544..2f3b193274 100644 --- a/tests/qapi-schema/leading-comma-object.err +++ b/tests/qapi-schema/leading-comma-object.err @@ -1 +1 @@ -tests/qapi-schema/leading-comma-object.json:1:3: Expected string or "}" +tests/qapi-schema/leading-comma-object.json:1:3: expected string or '}' diff --git a/tests/qapi-schema/missing-colon.err b/tests/qapi-schema/missing-colon.err index d9d66b377a..e642c7c549 100644 --- a/tests/qapi-schema/missing-colon.err +++ b/tests/qapi-schema/missing-colon.err @@ -1 +1 @@ -tests/qapi-schema/missing-colon.json:1:10: Expected ":" +tests/qapi-schema/missing-colon.json:1:10: expected ':' diff --git a/tests/qapi-schema/missing-comma-list.err b/tests/qapi-schema/missing-comma-list.err index e73d2770d6..5359499430 100644 --- a/tests/qapi-schema/missing-comma-list.err +++ b/tests/qapi-schema/missing-comma-list.err @@ -1 +1 @@ -tests/qapi-schema/missing-comma-list.json:2:20: Expected "," or "]" +tests/qapi-schema/missing-comma-list.json:2:20: expected ',' or ']' diff --git a/tests/qapi-schema/missing-comma-object.err b/tests/qapi-schema/missing-comma-object.err index 52b3a8a1ec..c9b02b0760 100644 --- a/tests/qapi-schema/missing-comma-object.err +++ b/tests/qapi-schema/missing-comma-object.err @@ -1 +1 @@ -tests/qapi-schema/missing-comma-object.json:2:3: Expected "," or "}" +tests/qapi-schema/missing-comma-object.json:2:3: expected ',' or '}' diff --git a/tests/qapi-schema/missing-type.err b/tests/qapi-schema/missing-type.err index b3e7b14e42..19b7c495e7 100644 --- a/tests/qapi-schema/missing-type.err +++ b/tests/qapi-schema/missing-type.err @@ -1 +1 @@ -tests/qapi-schema/missing-type.json:2: Expression is missing metatype +tests/qapi-schema/missing-type.json:2: expression is missing metatype diff --git a/tests/qapi-schema/nested-struct-data-invalid-dict.err b/tests/qapi-schema/nested-struct-data-invalid-dict.err index 5bd364e8d9..ed42d6323e 100644 --- a/tests/qapi-schema/nested-struct-data-invalid-dict.err +++ b/tests/qapi-schema/nested-struct-data-invalid-dict.err @@ -1 +1,2 @@ -tests/qapi-schema/nested-struct-data-invalid-dict.json:2: Key 'type' is missing from member 'a' of 'data' for command 'foo' +tests/qapi-schema/nested-struct-data-invalid-dict.json: In command 'foo': +tests/qapi-schema/nested-struct-data-invalid-dict.json:2: 'data' member 'a' misses key 'type' diff --git a/tests/qapi-schema/nested-struct-data.err b/tests/qapi-schema/nested-struct-data.err index da767bade2..b0ec410eb7 100644 --- a/tests/qapi-schema/nested-struct-data.err +++ b/tests/qapi-schema/nested-struct-data.err @@ -1 +1,2 @@ -tests/qapi-schema/nested-struct-data.json:2: Member 'a' of 'data' for command 'foo' should be a type name +tests/qapi-schema/nested-struct-data.json: In command 'foo': +tests/qapi-schema/nested-struct-data.json:2: 'data' member 'a' should be a type name diff --git a/tests/qapi-schema/non-objects.err b/tests/qapi-schema/non-objects.err index 334f0c91ae..9237af6939 100644 --- a/tests/qapi-schema/non-objects.err +++ b/tests/qapi-schema/non-objects.err @@ -1 +1 @@ -tests/qapi-schema/non-objects.json:1:1: Expected "{" +tests/qapi-schema/non-objects.json:1:1: expected '{' diff --git a/tests/qapi-schema/oob-test.err b/tests/qapi-schema/oob-test.err index 35b60f7480..3c2ba6e0fd 100644 --- a/tests/qapi-schema/oob-test.err +++ b/tests/qapi-schema/oob-test.err @@ -1 +1,2 @@ -tests/qapi-schema/oob-test.json:2: 'allow-oob' of command 'oob-command-1' should only use true value +tests/qapi-schema/oob-test.json: In command 'oob-command-1': +tests/qapi-schema/oob-test.json:2: flag 'allow-oob' may only use true value diff --git a/tests/qapi-schema/pragma-doc-required-crap.err b/tests/qapi-schema/pragma-doc-required-crap.err index 39cd56cd48..bcd981ada8 100644 --- a/tests/qapi-schema/pragma-doc-required-crap.err +++ b/tests/qapi-schema/pragma-doc-required-crap.err @@ -1 +1 @@ -tests/qapi-schema/pragma-doc-required-crap.json:3: Pragma 'doc-required' must be boolean +tests/qapi-schema/pragma-doc-required-crap.json:3: pragma 'doc-required' must be boolean diff --git a/tests/qapi-schema/pragma-extra-junk.err b/tests/qapi-schema/pragma-extra-junk.err index 4481688dbf..3ae48d3668 100644 --- a/tests/qapi-schema/pragma-extra-junk.err +++ b/tests/qapi-schema/pragma-extra-junk.err @@ -1 +1 @@ -tests/qapi-schema/pragma-extra-junk.json:3: Invalid 'pragma' directive +tests/qapi-schema/pragma-extra-junk.json:3: invalid 'pragma' directive diff --git a/tests/qapi-schema/pragma-name-case-whitelist-crap.err b/tests/qapi-schema/pragma-name-case-whitelist-crap.err index f83b97e075..81f829ff36 100644 --- a/tests/qapi-schema/pragma-name-case-whitelist-crap.err +++ b/tests/qapi-schema/pragma-name-case-whitelist-crap.err @@ -1 +1 @@ -tests/qapi-schema/pragma-name-case-whitelist-crap.json:3: Pragma name-case-whitelist must be a list of strings +tests/qapi-schema/pragma-name-case-whitelist-crap.json:3: pragma name-case-whitelist must be a list of strings diff --git a/tests/qapi-schema/pragma-name-case-whitelist-crap.json b/tests/qapi-schema/pragma-name-case-whitelist-crap.json index 58382bf4e4..734e1c617b 100644 --- a/tests/qapi-schema/pragma-name-case-whitelist-crap.json +++ b/tests/qapi-schema/pragma-name-case-whitelist-crap.json @@ -1,3 +1,3 @@ # 'name-case-whitelist' must be list of strings -{ 'pragma': { 'name-case-whitelist': null } } +{ 'pragma': { 'name-case-whitelist': false } } diff --git a/tests/qapi-schema/pragma-non-dict.err b/tests/qapi-schema/pragma-non-dict.err index 75bc335aea..8221724b0a 100644 --- a/tests/qapi-schema/pragma-non-dict.err +++ b/tests/qapi-schema/pragma-non-dict.err @@ -1 +1 @@ -tests/qapi-schema/pragma-non-dict.json:3: Value of 'pragma' must be a dictionary +tests/qapi-schema/pragma-non-dict.json:3: value of 'pragma' must be an object diff --git a/tests/qapi-schema/pragma-returns-whitelist-crap.err b/tests/qapi-schema/pragma-returns-whitelist-crap.err index 5d77021674..c0cae5de18 100644 --- a/tests/qapi-schema/pragma-returns-whitelist-crap.err +++ b/tests/qapi-schema/pragma-returns-whitelist-crap.err @@ -1 +1 @@ -tests/qapi-schema/pragma-returns-whitelist-crap.json:3: Pragma returns-whitelist must be a list of strings +tests/qapi-schema/pragma-returns-whitelist-crap.json:3: pragma returns-whitelist must be a list of strings diff --git a/tests/qapi-schema/pragma-unknown.err b/tests/qapi-schema/pragma-unknown.err new file mode 100644 index 0000000000..f1335f0a0a --- /dev/null +++ b/tests/qapi-schema/pragma-unknown.err @@ -0,0 +1 @@ +tests/qapi-schema/pragma-unknown.json:1: unknown pragma 'no-such-pragma' diff --git a/tests/qapi-schema/escape-too-short.exit b/tests/qapi-schema/pragma-unknown.exit index d00491fd7e..d00491fd7e 100644 --- a/tests/qapi-schema/escape-too-short.exit +++ b/tests/qapi-schema/pragma-unknown.exit diff --git a/tests/qapi-schema/pragma-unknown.json b/tests/qapi-schema/pragma-unknown.json new file mode 100644 index 0000000000..c51bbbb53f --- /dev/null +++ b/tests/qapi-schema/pragma-unknown.json @@ -0,0 +1 @@ +{ 'pragma': { 'no-such-pragma': false } } diff --git a/tests/qapi-schema/escape-too-short.out b/tests/qapi-schema/pragma-unknown.out index e69de29bb2..e69de29bb2 100644 --- a/tests/qapi-schema/escape-too-short.out +++ b/tests/qapi-schema/pragma-unknown.out diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index c6d59acc3e..75c42eb0e3 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -25,6 +25,11 @@ { 'struct': 'Empty1', 'data': { } } { 'struct': 'Empty2', 'base': 'Empty1', 'data': { } } +# Likewise for an empty flat union +{ 'union': 'Union', + 'base': { 'type': 'EnumOne' }, 'discriminator': 'type', + 'data': { } } + { 'command': 'user_def_cmd0', 'data': 'Empty2', 'returns': 'Empty2' } # for testing override of default naming heuristic @@ -149,6 +154,7 @@ { 'command': 'guest-sync', 'data': { 'arg': 'any' }, 'returns': 'any' } { 'command': 'boxed-struct', 'boxed': true, 'data': 'UserDefZero' } { 'command': 'boxed-union', 'data': 'UserDefListUnion', 'boxed': true } +{ 'command': 'boxed-empty', 'boxed': true, 'data': 'Empty1' } # Smoke test on out-of-band and allow-preconfig-test { 'command': 'test-flags-command', 'allow-oob': true, 'allow-preconfig': true } @@ -180,23 +186,26 @@ { 'event': 'EVENT_D', 'data': { 'a' : 'EventStructOne', 'b' : 'str', '*c': 'str', '*enum3': 'EnumOne' } } { 'event': 'EVENT_E', 'boxed': true, 'data': 'UserDefZero' } -{ 'event': 'EVENT_F', 'boxed': true, 'data': 'UserDefAlternate' } +{ 'event': 'EVENT_F', 'boxed': true, 'data': 'UserDefFlatUnion' } +{ 'event': 'EVENT_G', 'boxed': true, 'data': 'Empty1' } # test that we correctly compile downstream extensions, as well as munge # ticklish names +# also test union and alternate with just one branch { 'enum': '__org.qemu_x-Enum', 'data': [ '__org.qemu_x-value' ] } { 'struct': '__org.qemu_x-Base', 'data': { '__org.qemu_x-member1': '__org.qemu_x-Enum' } } { 'struct': '__org.qemu_x-Struct', 'base': '__org.qemu_x-Base', 'data': { '__org.qemu_x-member2': 'str', '*wchar-t': 'int' } } { 'union': '__org.qemu_x-Union1', 'data': { '__org.qemu_x-branch': 'str' } } +{ 'alternate': '__org.qemu_x-Alt1', 'data': { '__org.qemu_x-branch': 'str' } } { 'struct': '__org.qemu_x-Struct2', 'data': { 'array': ['__org.qemu_x-Union1'] } } { 'union': '__org.qemu_x-Union2', 'base': '__org.qemu_x-Base', 'discriminator': '__org.qemu_x-member1', 'data': { '__org.qemu_x-value': '__org.qemu_x-Struct2' } } { 'alternate': '__org.qemu_x-Alt', - 'data': { '__org.qemu_x-branch': 'str', 'b': '__org.qemu_x-Base' } } + 'data': { '__org.qemu_x-branch': '__org.qemu_x-Base' } } { 'event': '__ORG.QEMU_X-EVENT', 'data': '__org.qemu_x-Struct' } { 'command': '__org.qemu_x-command', 'data': { 'a': ['__org.qemu_x-Enum'], 'b': ['__org.qemu_x-Struct'], diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index 85d510bc00..98031da96f 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -23,6 +23,15 @@ enum MyEnum object Empty1 object Empty2 base Empty1 +object q_obj_Union-base + member type: EnumOne optional=False +object Union + base q_obj_Union-base + tag type + case value1: q_empty + case value2: q_empty + case value3: q_empty + case value4: q_empty command user_def_cmd0 Empty2 -> Empty2 gen=True success_response=True boxed=False oob=False preconfig=False enum QEnumTwo @@ -221,6 +230,8 @@ command boxed-struct UserDefZero -> None gen=True success_response=True boxed=True oob=False preconfig=False command boxed-union UserDefListUnion -> None gen=True success_response=True boxed=True oob=False preconfig=False +command boxed-empty Empty1 -> None + gen=True success_response=True boxed=True oob=False preconfig=False command test-flags-command None -> None gen=True success_response=True boxed=False oob=True preconfig=True object UserDefOptions @@ -252,7 +263,9 @@ event EVENT_D q_obj_EVENT_D-arg boxed=False event EVENT_E UserDefZero boxed=True -event EVENT_F UserDefAlternate +event EVENT_F UserDefFlatUnion + boxed=True +event EVENT_G Empty1 boxed=True enum __org.qemu_x-Enum member __org.qemu_x-value @@ -270,6 +283,9 @@ object __org.qemu_x-Union1 member type: __org.qemu_x-Union1Kind optional=False tag type case __org.qemu_x-branch: q_obj_str-wrapper +alternate __org.qemu_x-Alt1 + tag type + case __org.qemu_x-branch: str array __org.qemu_x-Union1List __org.qemu_x-Union1 object __org.qemu_x-Struct2 member array: __org.qemu_x-Union1List optional=False @@ -279,8 +295,7 @@ object __org.qemu_x-Union2 case __org.qemu_x-value: __org.qemu_x-Struct2 alternate __org.qemu_x-Alt tag type - case __org.qemu_x-branch: str - case b: __org.qemu_x-Base + case __org.qemu_x-branch: __org.qemu_x-Base event __ORG.QEMU_X-EVENT __org.qemu_x-Struct boxed=False array __org.qemu_x-EnumList __org.qemu_x-Enum diff --git a/tests/qapi-schema/quoted-structural-chars.err b/tests/qapi-schema/quoted-structural-chars.err index 9b183841dd..d8460a63a7 100644 --- a/tests/qapi-schema/quoted-structural-chars.err +++ b/tests/qapi-schema/quoted-structural-chars.err @@ -1 +1 @@ -tests/qapi-schema/quoted-structural-chars.json:1:1: Expected "{" +tests/qapi-schema/quoted-structural-chars.json:1:1: expected '{' diff --git a/tests/qapi-schema/redefined-builtin.err b/tests/qapi-schema/redefined-builtin.err index b2757225c4..47c8933759 100644 --- a/tests/qapi-schema/redefined-builtin.err +++ b/tests/qapi-schema/redefined-builtin.err @@ -1 +1,2 @@ -tests/qapi-schema/redefined-builtin.json:2: built-in 'size' is already defined +tests/qapi-schema/redefined-builtin.json: In struct 'size': +tests/qapi-schema/redefined-builtin.json:2: built-in type 'size' is already defined diff --git a/tests/qapi-schema/redefined-command.err b/tests/qapi-schema/redefined-command.err index 82ae256e63..54e366bbf3 100644 --- a/tests/qapi-schema/redefined-command.err +++ b/tests/qapi-schema/redefined-command.err @@ -1 +1,4 @@ -tests/qapi-schema/redefined-command.json:3: command 'foo' is already defined +tests/qapi-schema/redefined-command.json: In command 'foo': +tests/qapi-schema/redefined-command.json:3: 'foo' is already defined +tests/qapi-schema/redefined-command.json: In command 'foo': +tests/qapi-schema/redefined-command.json:2: previous definition diff --git a/tests/qapi-schema/redefined-event.err b/tests/qapi-schema/redefined-event.err index 35429cb481..606c6e4497 100644 --- a/tests/qapi-schema/redefined-event.err +++ b/tests/qapi-schema/redefined-event.err @@ -1 +1,4 @@ -tests/qapi-schema/redefined-event.json:3: event 'EVENT_A' is already defined +tests/qapi-schema/redefined-event.json: In event 'EVENT_A': +tests/qapi-schema/redefined-event.json:3: 'EVENT_A' is already defined +tests/qapi-schema/redefined-event.json: In event 'EVENT_A': +tests/qapi-schema/redefined-event.json:2: previous definition diff --git a/tests/qapi-schema/redefined-type.err b/tests/qapi-schema/redefined-type.err index 06ea78c478..77786f98ae 100644 --- a/tests/qapi-schema/redefined-type.err +++ b/tests/qapi-schema/redefined-type.err @@ -1 +1,4 @@ -tests/qapi-schema/redefined-type.json:3: struct 'foo' is already defined +tests/qapi-schema/redefined-type.json: In enum 'foo': +tests/qapi-schema/redefined-type.json:3: 'foo' is already defined +tests/qapi-schema/redefined-type.json: In struct 'foo': +tests/qapi-schema/redefined-type.json:2: previous definition diff --git a/tests/qapi-schema/reserved-command-q.err b/tests/qapi-schema/reserved-command-q.err index f939e044eb..7f65cda02d 100644 --- a/tests/qapi-schema/reserved-command-q.err +++ b/tests/qapi-schema/reserved-command-q.err @@ -1 +1,2 @@ -tests/qapi-schema/reserved-command-q.json:5: 'command' uses invalid name 'q-unix' +tests/qapi-schema/reserved-command-q.json: In command 'q-unix': +tests/qapi-schema/reserved-command-q.json:5: command has an invalid name diff --git a/tests/qapi-schema/reserved-enum-q.err b/tests/qapi-schema/reserved-enum-q.err index e1c3480ee2..e202f9ff7b 100644 --- a/tests/qapi-schema/reserved-enum-q.err +++ b/tests/qapi-schema/reserved-enum-q.err @@ -1 +1,2 @@ -tests/qapi-schema/reserved-enum-q.json:4: Member of enum 'Foo' uses invalid name 'q-Unix' +tests/qapi-schema/reserved-enum-q.json: In enum 'Foo': +tests/qapi-schema/reserved-enum-q.json:4: 'data' member 'q-Unix' has an invalid name diff --git a/tests/qapi-schema/reserved-member-has.err b/tests/qapi-schema/reserved-member-has.err index e755771446..c7ad721ad1 100644 --- a/tests/qapi-schema/reserved-member-has.err +++ b/tests/qapi-schema/reserved-member-has.err @@ -1 +1,2 @@ -tests/qapi-schema/reserved-member-has.json:5: Member of 'data' for command 'oops' uses reserved name 'has-a' +tests/qapi-schema/reserved-member-has.json: In command 'oops': +tests/qapi-schema/reserved-member-has.json:5: 'data' member 'has-a' uses reserved name diff --git a/tests/qapi-schema/reserved-member-q.err b/tests/qapi-schema/reserved-member-q.err index f3d5dd7818..04078604fa 100644 --- a/tests/qapi-schema/reserved-member-q.err +++ b/tests/qapi-schema/reserved-member-q.err @@ -1 +1,2 @@ -tests/qapi-schema/reserved-member-q.json:4: Member of 'data' for struct 'Foo' uses invalid name 'q-unix' +tests/qapi-schema/reserved-member-q.json: In struct 'Foo': +tests/qapi-schema/reserved-member-q.json:4: 'data' member 'q-unix' has an invalid name diff --git a/tests/qapi-schema/reserved-member-u.err b/tests/qapi-schema/reserved-member-u.err index 87d42296cc..2e92c11ba5 100644 --- a/tests/qapi-schema/reserved-member-u.err +++ b/tests/qapi-schema/reserved-member-u.err @@ -1 +1,2 @@ -tests/qapi-schema/reserved-member-u.json:7: Member of 'data' for struct 'Oops' uses reserved name 'u' +tests/qapi-schema/reserved-member-u.json: In struct 'Oops': +tests/qapi-schema/reserved-member-u.json:7: 'data' member 'u' uses reserved name diff --git a/tests/qapi-schema/reserved-member-underscore.err b/tests/qapi-schema/reserved-member-underscore.err index 65ff0da8ce..da62b48222 100644 --- a/tests/qapi-schema/reserved-member-underscore.err +++ b/tests/qapi-schema/reserved-member-underscore.err @@ -1 +1,2 @@ -tests/qapi-schema/reserved-member-underscore.json:4: Member of 'data' for struct 'Oops' uses invalid name '_oops' +tests/qapi-schema/reserved-member-underscore.json: In struct 'Oops': +tests/qapi-schema/reserved-member-underscore.json:4: 'data' member '_oops' has an invalid name diff --git a/tests/qapi-schema/reserved-type-kind.err b/tests/qapi-schema/reserved-type-kind.err index 0a38efaad8..f8112cf92e 100644 --- a/tests/qapi-schema/reserved-type-kind.err +++ b/tests/qapi-schema/reserved-type-kind.err @@ -1 +1,2 @@ -tests/qapi-schema/reserved-type-kind.json:2: enum 'UnionKind' should not end in 'Kind' +tests/qapi-schema/reserved-type-kind.json: In enum 'UnionKind': +tests/qapi-schema/reserved-type-kind.json:2: enum name should not end in 'Kind' diff --git a/tests/qapi-schema/reserved-type-list.err b/tests/qapi-schema/reserved-type-list.err index 4510fa6d90..c6eee0585c 100644 --- a/tests/qapi-schema/reserved-type-list.err +++ b/tests/qapi-schema/reserved-type-list.err @@ -1 +1,2 @@ -tests/qapi-schema/reserved-type-list.json:5: struct 'FooList' should not end in 'List' +tests/qapi-schema/reserved-type-list.json: In struct 'FooList': +tests/qapi-schema/reserved-type-list.json:5: struct name should not end in 'List' diff --git a/tests/qapi-schema/returns-alternate.err b/tests/qapi-schema/returns-alternate.err index dfbb419cac..c1caf98c47 100644 --- a/tests/qapi-schema/returns-alternate.err +++ b/tests/qapi-schema/returns-alternate.err @@ -1 +1,2 @@ -tests/qapi-schema/returns-alternate.json:3: 'returns' for command 'oops' cannot use alternate type 'Alt' +tests/qapi-schema/returns-alternate.json: In command 'oops': +tests/qapi-schema/returns-alternate.json:3: command's 'returns' cannot take alternate type 'Alt' diff --git a/tests/qapi-schema/returns-array-bad.err b/tests/qapi-schema/returns-array-bad.err index 138095ccde..1b86777d8f 100644 --- a/tests/qapi-schema/returns-array-bad.err +++ b/tests/qapi-schema/returns-array-bad.err @@ -1 +1,2 @@ -tests/qapi-schema/returns-array-bad.json:2: 'returns' for command 'oops': array type must contain single type name +tests/qapi-schema/returns-array-bad.json: In command 'oops': +tests/qapi-schema/returns-array-bad.json:2: 'returns': array type must contain single type name diff --git a/tests/qapi-schema/returns-dict.err b/tests/qapi-schema/returns-dict.err index eb2d0c4661..52e4f3ad71 100644 --- a/tests/qapi-schema/returns-dict.err +++ b/tests/qapi-schema/returns-dict.err @@ -1 +1,2 @@ -tests/qapi-schema/returns-dict.json:2: 'returns' for command 'oops' should be a type name +tests/qapi-schema/returns-dict.json: In command 'oops': +tests/qapi-schema/returns-dict.json:2: 'returns' should be a type name diff --git a/tests/qapi-schema/returns-unknown.err b/tests/qapi-schema/returns-unknown.err index 1f43e3ac9f..f0a989a175 100644 --- a/tests/qapi-schema/returns-unknown.err +++ b/tests/qapi-schema/returns-unknown.err @@ -1 +1,2 @@ -tests/qapi-schema/returns-unknown.json:2: 'returns' for command 'oops' uses unknown type 'NoSuchType' +tests/qapi-schema/returns-unknown.json: In command 'oops': +tests/qapi-schema/returns-unknown.json:2: command's 'returns' uses unknown type 'NoSuchType' diff --git a/tests/qapi-schema/returns-whitelist.err b/tests/qapi-schema/returns-whitelist.err index b2ba7a9deb..5b0285220f 100644 --- a/tests/qapi-schema/returns-whitelist.err +++ b/tests/qapi-schema/returns-whitelist.err @@ -1 +1,2 @@ -tests/qapi-schema/returns-whitelist.json:14: 'returns' for command 'no-way-this-will-get-whitelisted' cannot use built-in type 'int' +tests/qapi-schema/returns-whitelist.json: In command 'no-way-this-will-get-whitelisted': +tests/qapi-schema/returns-whitelist.json:14: command's 'returns' cannot take array type ['int'] diff --git a/tests/qapi-schema/string-code-point-127.err b/tests/qapi-schema/string-code-point-127.err new file mode 100644 index 0000000000..b4fa2610a9 --- /dev/null +++ b/tests/qapi-schema/string-code-point-127.err @@ -0,0 +1 @@ +tests/qapi-schema/string-code-point-127.json:2:14: funny character in string diff --git a/tests/qapi-schema/include-format-err.exit b/tests/qapi-schema/string-code-point-127.exit index d00491fd7e..d00491fd7e 100644 --- a/tests/qapi-schema/include-format-err.exit +++ b/tests/qapi-schema/string-code-point-127.exit diff --git a/tests/qapi-schema/string-code-point-127.json b/tests/qapi-schema/string-code-point-127.json new file mode 100644 index 0000000000..480318a69f --- /dev/null +++ b/tests/qapi-schema/string-code-point-127.json @@ -0,0 +1,2 @@ +# We accept printable ASCII: code points 32..126. Test code point 127: +{ 'command': '' } diff --git a/tests/qapi-schema/include-format-err.out b/tests/qapi-schema/string-code-point-127.out index e69de29bb2..e69de29bb2 100644 --- a/tests/qapi-schema/include-format-err.out +++ b/tests/qapi-schema/string-code-point-127.out diff --git a/tests/qapi-schema/string-code-point-31.err b/tests/qapi-schema/string-code-point-31.err new file mode 100644 index 0000000000..0bb5ce37b8 --- /dev/null +++ b/tests/qapi-schema/string-code-point-31.err @@ -0,0 +1 @@ +tests/qapi-schema/string-code-point-31.json:2:14: funny character in string diff --git a/tests/qapi-schema/unicode-str.exit b/tests/qapi-schema/string-code-point-31.exit index d00491fd7e..d00491fd7e 100644 --- a/tests/qapi-schema/unicode-str.exit +++ b/tests/qapi-schema/string-code-point-31.exit diff --git a/tests/qapi-schema/string-code-point-31.json b/tests/qapi-schema/string-code-point-31.json new file mode 100644 index 0000000000..f186cbd720 --- /dev/null +++ b/tests/qapi-schema/string-code-point-31.json @@ -0,0 +1,2 @@ +# We accept printable ASCII: code points 32..126. Test code point 127: +{ 'command': '' } diff --git a/tests/qapi-schema/unicode-str.out b/tests/qapi-schema/string-code-point-31.out index e69de29bb2..e69de29bb2 100644 --- a/tests/qapi-schema/unicode-str.out +++ b/tests/qapi-schema/string-code-point-31.out diff --git a/tests/qapi-schema/struct-base-clash-deep.err b/tests/qapi-schema/struct-base-clash-deep.err index e2d7943f21..2b12b3c07f 100644 --- a/tests/qapi-schema/struct-base-clash-deep.err +++ b/tests/qapi-schema/struct-base-clash-deep.err @@ -1 +1,2 @@ -tests/qapi-schema/struct-base-clash-deep.json:10: 'name' (member of Sub) collides with 'name' (member of Base) +tests/qapi-schema/struct-base-clash-deep.json: In struct 'Sub': +tests/qapi-schema/struct-base-clash-deep.json:10: member 'name' collides with member 'name' of type 'Base' diff --git a/tests/qapi-schema/struct-base-clash.err b/tests/qapi-schema/struct-base-clash.err index c52f33d27b..8c3ee1c435 100644 --- a/tests/qapi-schema/struct-base-clash.err +++ b/tests/qapi-schema/struct-base-clash.err @@ -1 +1,2 @@ -tests/qapi-schema/struct-base-clash.json:5: 'name' (member of Sub) collides with 'name' (member of Base) +tests/qapi-schema/struct-base-clash.json: In struct 'Sub': +tests/qapi-schema/struct-base-clash.json:5: member 'name' collides with member 'name' of type 'Base' diff --git a/tests/qapi-schema/struct-data-invalid.err b/tests/qapi-schema/struct-data-invalid.err index 6644f4c2ad..aa868bf974 100644 --- a/tests/qapi-schema/struct-data-invalid.err +++ b/tests/qapi-schema/struct-data-invalid.err @@ -1 +1,2 @@ -tests/qapi-schema/struct-data-invalid.json:1: 'data' for struct 'foo' should be a dictionary or type name +tests/qapi-schema/struct-data-invalid.json: In struct 'foo': +tests/qapi-schema/struct-data-invalid.json:1: 'data' should be an object or type name diff --git a/tests/qapi-schema/struct-member-if-invalid.err b/tests/qapi-schema/struct-member-if-invalid.err new file mode 100644 index 0000000000..4c5983674b --- /dev/null +++ b/tests/qapi-schema/struct-member-if-invalid.err @@ -0,0 +1,2 @@ +tests/qapi-schema/struct-member-if-invalid.json: In struct 'Stru': +tests/qapi-schema/struct-member-if-invalid.json:2: 'if' condition of 'data' member 'member' must be a string or a list of strings diff --git a/tests/qapi-schema/struct-member-if-invalid.exit b/tests/qapi-schema/struct-member-if-invalid.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/struct-member-if-invalid.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/struct-member-if-invalid.json b/tests/qapi-schema/struct-member-if-invalid.json new file mode 100644 index 0000000000..35078bd660 --- /dev/null +++ b/tests/qapi-schema/struct-member-if-invalid.json @@ -0,0 +1,3 @@ +# Cover member with invalid 'if' +{ 'struct': 'Stru', + 'data': { 'member': { 'type': 'int', 'if': true } } } diff --git a/tests/qapi-schema/struct-member-if-invalid.out b/tests/qapi-schema/struct-member-if-invalid.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/struct-member-if-invalid.out diff --git a/tests/qapi-schema/struct-member-invalid-dict.err b/tests/qapi-schema/struct-member-invalid-dict.err index 6a765bc668..46ec991c28 100644 --- a/tests/qapi-schema/struct-member-invalid-dict.err +++ b/tests/qapi-schema/struct-member-invalid-dict.err @@ -1 +1,2 @@ -tests/qapi-schema/struct-member-invalid-dict.json:2: Key 'type' is missing from member '*a' of 'data' for struct 'foo' +tests/qapi-schema/struct-member-invalid-dict.json: In struct 'foo': +tests/qapi-schema/struct-member-invalid-dict.json:2: 'data' member '*a' misses key 'type' diff --git a/tests/qapi-schema/struct-member-invalid.err b/tests/qapi-schema/struct-member-invalid.err index 69a326d450..92d4973832 100644 --- a/tests/qapi-schema/struct-member-invalid.err +++ b/tests/qapi-schema/struct-member-invalid.err @@ -1 +1,2 @@ -tests/qapi-schema/struct-member-invalid.json:1: Member 'a' of 'data' for struct 'foo' should be a type name +tests/qapi-schema/struct-member-invalid.json: In struct 'foo': +tests/qapi-schema/struct-member-invalid.json:1: 'data' member 'a' should be a type name diff --git a/tests/qapi-schema/trailing-comma-list.err b/tests/qapi-schema/trailing-comma-list.err index 212e14ae28..167d688beb 100644 --- a/tests/qapi-schema/trailing-comma-list.err +++ b/tests/qapi-schema/trailing-comma-list.err @@ -1 +1 @@ -tests/qapi-schema/trailing-comma-list.json:2:36: Expected "{", "[", string, boolean or "null" +tests/qapi-schema/trailing-comma-list.json:2:36: expected '{', '[', string, boolean or 'null' diff --git a/tests/qapi-schema/trailing-comma-object.err b/tests/qapi-schema/trailing-comma-object.err index 30bce5e194..186df0fa45 100644 --- a/tests/qapi-schema/trailing-comma-object.err +++ b/tests/qapi-schema/trailing-comma-object.err @@ -1 +1 @@ -tests/qapi-schema/trailing-comma-object.json:2:38: Expected string +tests/qapi-schema/trailing-comma-object.json:2:38: expected string diff --git a/tests/qapi-schema/type-bypass-bad-gen.err b/tests/qapi-schema/type-bypass-bad-gen.err index a83c3c655d..1077651896 100644 --- a/tests/qapi-schema/type-bypass-bad-gen.err +++ b/tests/qapi-schema/type-bypass-bad-gen.err @@ -1 +1,2 @@ -tests/qapi-schema/type-bypass-bad-gen.json:2: 'gen' of command 'foo' should only use false value +tests/qapi-schema/type-bypass-bad-gen.json: In command 'foo': +tests/qapi-schema/type-bypass-bad-gen.json:2: flag 'gen' may only use false value diff --git a/tests/qapi-schema/unclosed-list.err b/tests/qapi-schema/unclosed-list.err index fb41a86abd..6648a8e30b 100644 --- a/tests/qapi-schema/unclosed-list.err +++ b/tests/qapi-schema/unclosed-list.err @@ -1 +1 @@ -tests/qapi-schema/unclosed-list.json:1:20: Expected "," or "]" +tests/qapi-schema/unclosed-list.json:1:20: expected ',' or ']' diff --git a/tests/qapi-schema/unclosed-object.err b/tests/qapi-schema/unclosed-object.err index db3deedd63..54d221e3a9 100644 --- a/tests/qapi-schema/unclosed-object.err +++ b/tests/qapi-schema/unclosed-object.err @@ -1 +1 @@ -tests/qapi-schema/unclosed-object.json:1:21: Expected "," or "}" +tests/qapi-schema/unclosed-object.json:1:21: expected ',' or '}' diff --git a/tests/qapi-schema/unclosed-string.err b/tests/qapi-schema/unclosed-string.err index 12b187074e..9439698fe0 100644 --- a/tests/qapi-schema/unclosed-string.err +++ b/tests/qapi-schema/unclosed-string.err @@ -1 +1 @@ -tests/qapi-schema/unclosed-string.json:1:11: Missing terminating "'" +tests/qapi-schema/unclosed-string.json:1:11: missing terminating "'" diff --git a/tests/qapi-schema/unicode-str.err b/tests/qapi-schema/unicode-str.err deleted file mode 100644 index f621cd6448..0000000000 --- a/tests/qapi-schema/unicode-str.err +++ /dev/null @@ -1 +0,0 @@ -tests/qapi-schema/unicode-str.json:2: 'command' uses invalid name 'Ă©' diff --git a/tests/qapi-schema/unicode-str.json b/tests/qapi-schema/unicode-str.json deleted file mode 100644 index 5253a1b9f3..0000000000 --- a/tests/qapi-schema/unicode-str.json +++ /dev/null @@ -1,2 +0,0 @@ -# we don't support full Unicode strings, yet -{ 'command': 'Ă©' } diff --git a/tests/qapi-schema/union-base-empty.err b/tests/qapi-schema/union-base-empty.err index 7695806d81..b76542d47a 100644 --- a/tests/qapi-schema/union-base-empty.err +++ b/tests/qapi-schema/union-base-empty.err @@ -1 +1,2 @@ -tests/qapi-schema/union-base-empty.json:5: Discriminator 'type' is not a member of base struct 'Empty' +tests/qapi-schema/union-base-empty.json: In union 'TestUnion': +tests/qapi-schema/union-base-empty.json:5: discriminator 'type' is not a member of 'base' diff --git a/tests/qapi-schema/union-base-no-discriminator.err b/tests/qapi-schema/union-base-no-discriminator.err index 8b7a24260f..f4c16a2c14 100644 --- a/tests/qapi-schema/union-base-no-discriminator.err +++ b/tests/qapi-schema/union-base-no-discriminator.err @@ -1 +1,2 @@ -tests/qapi-schema/union-base-no-discriminator.json:11: Simple union 'TestUnion' must not have a base +tests/qapi-schema/union-base-no-discriminator.json: In union 'TestUnion': +tests/qapi-schema/union-base-no-discriminator.json:11: 'base' requires 'discriminator' diff --git a/tests/qapi-schema/union-branch-case.err b/tests/qapi-schema/union-branch-case.err index 11521901d8..a0684ae637 100644 --- a/tests/qapi-schema/union-branch-case.err +++ b/tests/qapi-schema/union-branch-case.err @@ -1 +1,2 @@ -tests/qapi-schema/union-branch-case.json:2: 'Branch' (branch of NoWayThisWillGetWhitelisted) should not use uppercase +tests/qapi-schema/union-branch-case.json: In union 'Uni': +tests/qapi-schema/union-branch-case.json:2: 'data' member 'Branch' uses uppercase in name diff --git a/tests/qapi-schema/union-branch-case.json b/tests/qapi-schema/union-branch-case.json index e6565dc3b3..b7894b75d6 100644 --- a/tests/qapi-schema/union-branch-case.json +++ b/tests/qapi-schema/union-branch-case.json @@ -1,2 +1,2 @@ -# Branch names should be 'lower-case' unless the union is whitelisted -{ 'union': 'NoWayThisWillGetWhitelisted', 'data': { 'Branch': 'int' } } +# Branch names should be 'lower-case' +{ 'union': 'Uni', 'data': { 'Branch': 'int' } } diff --git a/tests/qapi-schema/union-branch-if-invalid.err b/tests/qapi-schema/union-branch-if-invalid.err new file mode 100644 index 0000000000..14819bf8b8 --- /dev/null +++ b/tests/qapi-schema/union-branch-if-invalid.err @@ -0,0 +1,2 @@ +tests/qapi-schema/union-branch-if-invalid.json: In union 'Uni': +tests/qapi-schema/union-branch-if-invalid.json:4: 'if' condition '' of 'data' member 'branch1' makes no sense diff --git a/tests/qapi-schema/union-branch-if-invalid.exit b/tests/qapi-schema/union-branch-if-invalid.exit new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/qapi-schema/union-branch-if-invalid.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/union-branch-if-invalid.json b/tests/qapi-schema/union-branch-if-invalid.json new file mode 100644 index 0000000000..46d4239af6 --- /dev/null +++ b/tests/qapi-schema/union-branch-if-invalid.json @@ -0,0 +1,6 @@ +# Cover branch with invalid 'if' +{ 'enum': 'Branches', 'data': ['branch1'] } +{ 'struct': 'Stru', 'data': { 'member': 'str' } } +{ 'union': 'Uni', + 'base': { 'tag': 'Branches' }, 'discriminator': 'tag', + 'data': { 'branch1': { 'type': 'Stru', 'if': [''] } } } diff --git a/tests/qapi-schema/union-branch-if-invalid.out b/tests/qapi-schema/union-branch-if-invalid.out new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/qapi-schema/union-branch-if-invalid.out diff --git a/tests/qapi-schema/union-branch-invalid-dict.err b/tests/qapi-schema/union-branch-invalid-dict.err index 89f9b36791..2967cd6260 100644 --- a/tests/qapi-schema/union-branch-invalid-dict.err +++ b/tests/qapi-schema/union-branch-invalid-dict.err @@ -1 +1,2 @@ -tests/qapi-schema/union-branch-invalid-dict.json:2: Key 'type' is missing from member 'integer' of union 'UnionInvalidBranch' +tests/qapi-schema/union-branch-invalid-dict.json: In union 'UnionInvalidBranch': +tests/qapi-schema/union-branch-invalid-dict.json:2: 'data' member 'integer' misses key 'type' diff --git a/tests/qapi-schema/union-clash-branches.err b/tests/qapi-schema/union-clash-branches.err index e5b21135bb..931399f076 100644 --- a/tests/qapi-schema/union-clash-branches.err +++ b/tests/qapi-schema/union-clash-branches.err @@ -1 +1,2 @@ -tests/qapi-schema/union-clash-branches.json:4: 'a_b' (branch of TestUnion) collides with 'a-b' (branch of TestUnion) +tests/qapi-schema/union-clash-branches.json: In union 'TestUnion': +tests/qapi-schema/union-clash-branches.json:4: branch 'a_b' collides with branch 'a-b' diff --git a/tests/qapi-schema/union-empty.err b/tests/qapi-schema/union-empty.err index 12c20221bd..35c0d62eb0 100644 --- a/tests/qapi-schema/union-empty.err +++ b/tests/qapi-schema/union-empty.err @@ -1 +1,2 @@ -tests/qapi-schema/union-empty.json:2: Union 'Union' cannot have empty 'data' +tests/qapi-schema/union-empty.json: In union 'Union': +tests/qapi-schema/union-empty.json:2: union has no branches diff --git a/tests/qapi-schema/union-empty.json b/tests/qapi-schema/union-empty.json index 1f0b13ca21..df3e5e639a 100644 --- a/tests/qapi-schema/union-empty.json +++ b/tests/qapi-schema/union-empty.json @@ -1,2 +1,2 @@ -# unions cannot be empty +# simple unions cannot be empty { 'union': 'Union', 'data': { } } diff --git a/tests/qapi-schema/union-invalid-base.err b/tests/qapi-schema/union-invalid-base.err index 03d7b97a93..10fecf0b56 100644 --- a/tests/qapi-schema/union-invalid-base.err +++ b/tests/qapi-schema/union-invalid-base.err @@ -1 +1,2 @@ -tests/qapi-schema/union-invalid-base.json:8: 'base' for union 'TestUnion' cannot use built-in type 'int' +tests/qapi-schema/union-invalid-base.json: In union 'TestUnion': +tests/qapi-schema/union-invalid-base.json:8: 'base' requires a struct type, built-in type 'int' isn't diff --git a/tests/qapi-schema/union-optional-branch.err b/tests/qapi-schema/union-optional-branch.err index 3ada1334dc..9f24274923 100644 --- a/tests/qapi-schema/union-optional-branch.err +++ b/tests/qapi-schema/union-optional-branch.err @@ -1 +1,2 @@ -tests/qapi-schema/union-optional-branch.json:2: Member of union 'Union' does not allow optional name '*a' +tests/qapi-schema/union-optional-branch.json: In union 'Union': +tests/qapi-schema/union-optional-branch.json:2: 'data' member '*a' has an invalid name diff --git a/tests/qapi-schema/union-unknown.err b/tests/qapi-schema/union-unknown.err index 54fe456f9c..a7f340ddca 100644 --- a/tests/qapi-schema/union-unknown.err +++ b/tests/qapi-schema/union-unknown.err @@ -1 +1,2 @@ -tests/qapi-schema/union-unknown.json:2: Member 'unknown' of union 'Union' uses unknown type 'MissingType' +tests/qapi-schema/union-unknown.json: In union 'Union': +tests/qapi-schema/union-unknown.json:2: union uses unknown type 'MissingType' diff --git a/tests/qapi-schema/union-unknown.json b/tests/qapi-schema/union-unknown.json index aa7e8143d8..64d3666176 100644 --- a/tests/qapi-schema/union-unknown.json +++ b/tests/qapi-schema/union-unknown.json @@ -1,3 +1,3 @@ # we reject a union with unknown type in branch { 'union': 'Union', - 'data': { 'unknown': 'MissingType' } } + 'data': { 'unknown': ['MissingType'] } } diff --git a/tests/qapi-schema/unknown-escape.err b/tests/qapi-schema/unknown-escape.err index 000e30ddf3..e24bbaf046 100644 --- a/tests/qapi-schema/unknown-escape.err +++ b/tests/qapi-schema/unknown-escape.err @@ -1 +1 @@ -tests/qapi-schema/unknown-escape.json:3:21: Unknown escape \x +tests/qapi-schema/unknown-escape.json:3:21: unknown escape \x diff --git a/tests/qapi-schema/unknown-escape.json b/tests/qapi-schema/unknown-escape.json index 8e6891e52a..8372e8024f 100644 --- a/tests/qapi-schema/unknown-escape.json +++ b/tests/qapi-schema/unknown-escape.json @@ -1,3 +1,3 @@ -# we only recognize JSON escape sequences, plus our \' extension (no \x) +# we only recognize \\ # { 'command': 'foo', 'data': {} } { 'command': 'foo', 'dat\x61':{} } diff --git a/tests/qapi-schema/unknown-expr-key.err b/tests/qapi-schema/unknown-expr-key.err index 4340eaf894..be9f99c4ef 100644 --- a/tests/qapi-schema/unknown-expr-key.err +++ b/tests/qapi-schema/unknown-expr-key.err @@ -1,2 +1,3 @@ -tests/qapi-schema/unknown-expr-key.json:2: Unknown keys 'bogus', 'phony' in struct 'bar' +tests/qapi-schema/unknown-expr-key.json: In struct 'bar': +tests/qapi-schema/unknown-expr-key.json:2: struct has unknown keys 'bogus', 'phony' Valid keys are 'base', 'data', 'features', 'if', 'struct'. diff --git a/tests/qemu-iotests/044 b/tests/qemu-iotests/044 index 05ea1f49c5..8b2afa2a11 100755 --- a/tests/qemu-iotests/044 +++ b/tests/qemu-iotests/044 @@ -28,9 +28,6 @@ import struct import subprocess import sys -if sys.version_info.major == 2: - range = xrange - test_img = os.path.join(iotests.test_dir, 'test.img') class TestRefcountTableGrowth(iotests.QMPTestCase): diff --git a/tests/qemu-iotests/163 b/tests/qemu-iotests/163 index 081ccc8ac1..d94728e080 100755 --- a/tests/qemu-iotests/163 +++ b/tests/qemu-iotests/163 @@ -21,9 +21,6 @@ import os, random, iotests, struct, qcow2, sys from iotests import qemu_img, qemu_io, image_size -if sys.version_info.major == 2: - range = xrange - test_img = os.path.join(iotests.test_dir, 'test.img') check_img = os.path.join(iotests.test_dir, 'check.img') diff --git a/tests/qemu-iotests/223 b/tests/qemu-iotests/223 index cc48e78ea7..2ba3d8124b 100755 --- a/tests/qemu-iotests/223 +++ b/tests/qemu-iotests/223 @@ -2,7 +2,7 @@ # # Test reading dirty bitmap over NBD # -# Copyright (C) 2018 Red Hat, Inc. +# Copyright (C) 2018-2019 Red Hat, Inc. # # 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 @@ -109,7 +109,7 @@ echo echo "=== End dirty bitmaps, and start serving image over NBD ===" echo -_launch_qemu 2> >(_filter_nbd) +_launch_qemu -object iothread,id=io0 2> >(_filter_nbd) # Intentionally provoke some errors as well, to check error handling silent= @@ -117,6 +117,8 @@ _send_qemu_cmd $QEMU_HANDLE '{"execute":"qmp_capabilities"}' "return" _send_qemu_cmd $QEMU_HANDLE '{"execute":"blockdev-add", "arguments":{"driver":"qcow2", "node-name":"n", "file":{"driver":"file", "filename":"'"$TEST_IMG"'"}}}' "return" +_send_qemu_cmd $QEMU_HANDLE '{"execute":"x-blockdev-set-iothread", + "arguments":{"node-name":"n", "iothread":"io0"}}' "return" _send_qemu_cmd $QEMU_HANDLE '{"execute":"block-dirty-bitmap-disable", "arguments":{"node":"n", "name":"b"}}' "return" _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add", diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out index 5d00398c11..23b34fcd20 100644 --- a/tests/qemu-iotests/223.out +++ b/tests/qemu-iotests/223.out @@ -27,6 +27,7 @@ wrote 2097152/2097152 bytes at offset 2097152 {"return": {}} {"return": {}} {"return": {}} +{"return": {}} {"error": {"class": "GenericError", "desc": "NBD server not running"}} {"return": {}} {"error": {"class": "GenericError", "desc": "NBD server already running"}} diff --git a/tests/qemu-iotests/233.out b/tests/qemu-iotests/233.out index 24321efa11..c3c344811b 100644 --- a/tests/qemu-iotests/233.out +++ b/tests/qemu-iotests/233.out @@ -21,8 +21,10 @@ server reported: TLS not configured == check plain client to TLS server fails == qemu-img: Could not open 'nbd://localhost:PORT': TLS negotiation required before option 7 (go) +Did you forget a valid tls-creds? server reported: Option 0x7 not permitted before TLS qemu-nbd: TLS negotiation required before option 3 (list) +Did you forget a valid tls-creds? server reported: Option 0x3 not permitted before TLS == check TLS works == diff --git a/tests/qemu-iotests/267 b/tests/qemu-iotests/267 new file mode 100755 index 0000000000..d37a67c012 --- /dev/null +++ b/tests/qemu-iotests/267 @@ -0,0 +1,168 @@ +#!/usr/bin/env bash +# +# Test which nodes are involved in internal snapshots +# +# Copyright (C) 2019 Red Hat, Inc. +# +# 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. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +# creator +owner=kwolf@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img + rm -f "$TEST_DIR/nbd" +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt qcow2 +_supported_proto file +_supported_os Linux + +# Internal snapshots are (currently) impossible with refcount_bits=1 +_unsupported_imgopts 'refcount_bits=1[^0-9]' + +do_run_qemu() +{ + echo Testing: "$@" + ( + if ! test -t 0; then + while read cmd; do + echo $cmd + done + fi + echo quit + ) | $QEMU -nographic -monitor stdio -nodefaults "$@" + echo +} + +run_qemu() +{ + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_hmp | + _filter_generated_node_ids | _filter_imgfmt | _filter_vmstate_size +} + +size=128M + +run_test() +{ + _make_test_img $size + printf "savevm snap0\ninfo snapshots\nloadvm snap0\n" | run_qemu "$@" | _filter_date +} + + +echo +echo "=== No block devices at all ===" +echo + +run_test + +echo +echo "=== -drive if=none ===" +echo + +run_test -drive driver=file,file="$TEST_IMG",if=none +run_test -drive driver=$IMGFMT,file="$TEST_IMG",if=none +run_test -drive driver=$IMGFMT,file="$TEST_IMG",if=none -device virtio-blk,drive=none0 + +echo +echo "=== -drive if=virtio ===" +echo + +run_test -drive driver=file,file="$TEST_IMG",if=virtio +run_test -drive driver=$IMGFMT,file="$TEST_IMG",if=virtio + +echo +echo "=== Simple -blockdev ===" +echo + +run_test -blockdev driver=file,filename="$TEST_IMG",node-name=file +run_test -blockdev driver=file,filename="$TEST_IMG",node-name=file \ + -blockdev driver=$IMGFMT,file=file,node-name=fmt +run_test -blockdev driver=file,filename="$TEST_IMG",node-name=file \ + -blockdev driver=raw,file=file,node-name=raw \ + -blockdev driver=$IMGFMT,file=raw,node-name=fmt + +echo +echo "=== -blockdev with a filter on top ===" +echo + +run_test -blockdev driver=file,filename="$TEST_IMG",node-name=file \ + -blockdev driver=$IMGFMT,file=file,node-name=fmt \ + -blockdev driver=copy-on-read,file=fmt,node-name=filter + +echo +echo "=== -blockdev with a backing file ===" +echo + +TEST_IMG="$TEST_IMG.base" _make_test_img $size + +IMGOPTS="backing_file=$TEST_IMG.base" \ +run_test -blockdev driver=file,filename="$TEST_IMG.base",node-name=backing-file \ + -blockdev driver=file,filename="$TEST_IMG",node-name=file \ + -blockdev driver=$IMGFMT,file=file,backing=backing-file,node-name=fmt + +IMGOPTS="backing_file=$TEST_IMG.base" \ +run_test -blockdev driver=file,filename="$TEST_IMG.base",node-name=backing-file \ + -blockdev driver=$IMGFMT,file=backing-file,node-name=backing-fmt \ + -blockdev driver=file,filename="$TEST_IMG",node-name=file \ + -blockdev driver=$IMGFMT,file=file,backing=backing-fmt,node-name=fmt + +# A snapshot should be present on the overlay, but not the backing file +echo Internal snapshots on overlay: +$QEMU_IMG snapshot -l "$TEST_IMG" | _filter_date | _filter_vmstate_size + +echo Internal snapshots on backing file: +$QEMU_IMG snapshot -l "$TEST_IMG.base" | _filter_date | _filter_vmstate_size + +echo +echo "=== -blockdev with NBD server on the backing file ===" +echo + +IMGOPTS="backing_file=$TEST_IMG.base" _make_test_img $size +cat <<EOF | +nbd_server_start unix:$TEST_DIR/nbd +nbd_server_add -w backing-fmt +savevm snap0 +info snapshots +loadvm snap0 +EOF +run_qemu -blockdev driver=file,filename="$TEST_IMG.base",node-name=backing-file \ + -blockdev driver=$IMGFMT,file=backing-file,node-name=backing-fmt \ + -blockdev driver=file,filename="$TEST_IMG",node-name=file \ + -blockdev driver=$IMGFMT,file=file,backing=backing-fmt,node-name=fmt | + _filter_date + +# This time, a snapshot should be created on both files +echo Internal snapshots on overlay: +$QEMU_IMG snapshot -l "$TEST_IMG" | _filter_date | _filter_vmstate_size + +echo Internal snapshots on backing file: +$QEMU_IMG snapshot -l "$TEST_IMG.base" | _filter_date | _filter_vmstate_size + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/267.out b/tests/qemu-iotests/267.out new file mode 100644 index 0000000000..9d812e3c72 --- /dev/null +++ b/tests/qemu-iotests/267.out @@ -0,0 +1,182 @@ +QA output created by 267 + +=== No block devices at all === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 +Testing: +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) savevm snap0 +Error: No block device can accept snapshots +(qemu) info snapshots +No available block device supports snapshots +(qemu) loadvm snap0 +Error: No block device supports snapshots +(qemu) quit + + +=== -drive if=none === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 +Testing: -drive driver=file,file=TEST_DIR/t.IMGFMT,if=none +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) savevm snap0 +Error: Device 'none0' is writable but does not support snapshots +(qemu) info snapshots +No available block device supports snapshots +(qemu) loadvm snap0 +Error: Device 'none0' is writable but does not support snapshots +(qemu) quit + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 +Testing: -drive driver=IMGFMT,file=TEST_DIR/t.IMGFMT,if=none +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) savevm snap0 +(qemu) info snapshots +List of snapshots present on all disks: +ID TAG VM SIZE DATE VM CLOCK +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 +(qemu) loadvm snap0 +(qemu) quit + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 +Testing: -drive driver=IMGFMT,file=TEST_DIR/t.IMGFMT,if=none -device virtio-blk,drive=none0 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) savevm snap0 +(qemu) info snapshots +List of snapshots present on all disks: +ID TAG VM SIZE DATE VM CLOCK +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 +(qemu) loadvm snap0 +(qemu) quit + + +=== -drive if=virtio === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 +Testing: -drive driver=file,file=TEST_DIR/t.IMGFMT,if=virtio +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) savevm snap0 +Error: Device 'virtio0' is writable but does not support snapshots +(qemu) info snapshots +No available block device supports snapshots +(qemu) loadvm snap0 +Error: Device 'virtio0' is writable but does not support snapshots +(qemu) quit + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 +Testing: -drive driver=IMGFMT,file=TEST_DIR/t.IMGFMT,if=virtio +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) savevm snap0 +(qemu) info snapshots +List of snapshots present on all disks: +ID TAG VM SIZE DATE VM CLOCK +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 +(qemu) loadvm snap0 +(qemu) quit + + +=== Simple -blockdev === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 +Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=file +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) savevm snap0 +Error: Device '' is writable but does not support snapshots +(qemu) info snapshots +No available block device supports snapshots +(qemu) loadvm snap0 +Error: Device '' is writable but does not support snapshots +(qemu) quit + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 +Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=file -blockdev driver=IMGFMT,file=file,node-name=fmt +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) savevm snap0 +(qemu) info snapshots +List of snapshots present on all disks: +ID TAG VM SIZE DATE VM CLOCK +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 +(qemu) loadvm snap0 +(qemu) quit + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 +Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=file -blockdev driver=raw,file=file,node-name=raw -blockdev driver=IMGFMT,file=raw,node-name=fmt +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) savevm snap0 +(qemu) info snapshots +List of snapshots present on all disks: +ID TAG VM SIZE DATE VM CLOCK +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 +(qemu) loadvm snap0 +(qemu) quit + + +=== -blockdev with a filter on top === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 +Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=file -blockdev driver=IMGFMT,file=file,node-name=fmt -blockdev driver=copy-on-read,file=fmt,node-name=filter +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) savevm snap0 +(qemu) info snapshots +List of snapshots present on all disks: +ID TAG VM SIZE DATE VM CLOCK +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 +(qemu) loadvm snap0 +(qemu) quit + + +=== -blockdev with a backing file === + +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base +Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT.base,node-name=backing-file -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=file -blockdev driver=IMGFMT,file=file,backing=backing-file,node-name=fmt +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) savevm snap0 +(qemu) info snapshots +List of snapshots present on all disks: +ID TAG VM SIZE DATE VM CLOCK +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 +(qemu) loadvm snap0 +(qemu) quit + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base +Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT.base,node-name=backing-file -blockdev driver=IMGFMT,file=backing-file,node-name=backing-fmt -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=file -blockdev driver=IMGFMT,file=file,backing=backing-fmt,node-name=fmt +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) savevm snap0 +(qemu) info snapshots +List of snapshots present on all disks: +ID TAG VM SIZE DATE VM CLOCK +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 +(qemu) loadvm snap0 +(qemu) quit + +Internal snapshots on overlay: +Snapshot list: +ID TAG VM SIZE DATE VM CLOCK +1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 +Internal snapshots on backing file: + +=== -blockdev with NBD server on the backing file === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base +Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT.base,node-name=backing-file -blockdev driver=IMGFMT,file=backing-file,node-name=backing-fmt -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=file -blockdev driver=IMGFMT,file=file,backing=backing-fmt,node-name=fmt +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) nbd_server_start unix:TEST_DIR/nbd +(qemu) nbd_server_add -w backing-fmt +(qemu) savevm snap0 +(qemu) info snapshots +List of snapshots present on all disks: +ID TAG VM SIZE DATE VM CLOCK +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 +(qemu) loadvm snap0 +(qemu) quit + +Internal snapshots on overlay: +Snapshot list: +ID TAG VM SIZE DATE VM CLOCK +1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 +Internal snapshots on backing file: +Snapshot list: +ID TAG VM SIZE DATE VM CLOCK +1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 +*** done diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check index 875399d79f..588c453a94 100755 --- a/tests/qemu-iotests/check +++ b/tests/qemu-iotests/check @@ -633,6 +633,12 @@ then export SOCKET_SCM_HELPER="$build_iotests/socket_scm_helper" fi +python_usable=false +if $PYTHON -c 'import sys; sys.exit(0 if sys.version_info >= (3,6) else 1)' +then + python_usable=true +fi + default_machine=$($QEMU_PROG -machine help | sed -n '/(default)/ s/ .*//p') default_alias_machine=$($QEMU_PROG -machine help | \ sed -n "/(alias of $default_machine)/ { s/ .*//p; q; }") @@ -809,7 +815,12 @@ do start=$(_wallclock) if [ "$(head -n 1 "$source_iotests/$seq")" == "#!/usr/bin/env python" ]; then - run_command="$PYTHON $seq" + if $python_usable; then + run_command="$PYTHON $seq" + else + run_command="false" + echo "Unsupported Python version" > $seq.notrun + fi else run_command="./$seq" fi diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index 445a1c23e0..9f418b4881 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -19,12 +19,15 @@ # standard filters # -# ctime(3) dates -# _filter_date() { - $SED \ - -e 's/[A-Z][a-z][a-z] [A-z][a-z][a-z] *[0-9][0-9]* [0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9][0-9][0-9][0-9]$/DATE/' + $SED -re 's/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/yyyy-mm-dd hh:mm:ss/' +} + +_filter_vmstate_size() +{ + $SED -r -e 's/[0-9. ]{5} [KMGT]iB/ SIZE/' \ + -e 's/[0-9. ]{5} B/ SIZE/' } _filter_generated_node_ids() diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 5d3da937e4..5805a79d9e 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -277,3 +277,4 @@ 263 rw quick 265 rw auto quick 266 rw quick +267 rw auto quick snapshot diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index b26271187c..9fb5181c3d 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -35,6 +35,7 @@ from collections import OrderedDict sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) from qemu import qtest +assert sys.version_info >= (3,6) # This will not work if arguments contain spaces but is necessary if we # want to support the override options that ./check supports. @@ -250,10 +251,7 @@ def image_size(img): return json.loads(r)['virtual-size'] def is_str(val): - if sys.version_info.major >= 3: - return isinstance(val, str) - else: - return isinstance(val, str) or isinstance(val, unicode) + return isinstance(val, str) test_dir_re = re.compile(r"%s" % test_dir) def filter_test_dir(msg): @@ -935,12 +933,7 @@ def execute_test(test_function=None, else: # We need to filter out the time taken from the output so that # qemu-iotest can reliably diff the results against master output. - if sys.version_info.major >= 3: - output = io.StringIO() - else: - # io.StringIO is for unicode strings, which is not what - # 2.x's test runner emits. - output = io.BytesIO() + output = io.StringIO() logging.basicConfig(level=(logging.DEBUG if debug else logging.WARN)) diff --git a/tests/tcg/Makefile.target b/tests/tcg/Makefile.target index 8808beaf74..5a9a6faba4 100644 --- a/tests/tcg/Makefile.target +++ b/tests/tcg/Makefile.target @@ -55,6 +55,15 @@ diff-out = $(call quiet-command, diff -q $1.out $2 || \ # $1 = test name, $2 = reason skip-test = @printf " SKIPPED %s on $(TARGET_NAME) because %s\n" $1 $2 +# $1 = test name, $2 = reference +# As above but only diff if reference file exists, otherwise the test +# passes if it managed to complete with a status of zero +conditional-diff-out = \ + $(if $(wildcard $2), \ + $(call diff-out,$1,$2), \ + $(call skip-test,"$1 check","no reference")) + + # Tests we are building TESTS= @@ -74,8 +83,11 @@ TIMEOUT=15 endif ifdef CONFIG_USER_ONLY -# The order we include is important. We include multiarch, base arch -# and finally arch if it's not the same as base arch. +# The order we include is important. We include multiarch first and +# then the target. If there are common tests shared between +# sub-targets (e.g. ARM & AArch64) then it is up to +# $(TARGET_NAME)/Makefile.target to include the common parent +# architecture in its VPATH. -include $(SRC_PATH)/tests/tcg/multiarch/Makefile.target -include $(SRC_PATH)/tests/tcg/$(TARGET_NAME)/Makefile.target diff --git a/tests/tcg/aarch64/Makefile.softmmu-target b/tests/tcg/aarch64/Makefile.softmmu-target index 4c4aaf61dd..b4b3957963 100644 --- a/tests/tcg/aarch64/Makefile.softmmu-target +++ b/tests/tcg/aarch64/Makefile.softmmu-target @@ -32,3 +32,24 @@ memory: CFLAGS+=-DCHECK_UNALIGNED=1 # Running QEMU_OPTS+=-M virt -cpu max -display none -semihosting-config enable=on,target=native,chardev=output -kernel + +# Simple Record/Replay Test +.PHONY: memory-record +run-memory-record: memory-record memory + $(call run-test, $<, \ + $(QEMU) -monitor none -display none \ + -chardev file$(COMMA)path=$<.out$(COMMA)id=output \ + -icount shift=5$(COMMA)rr=record$(COMMA)rrfile=record.bin \ + $(QEMU_OPTS) memory, \ + "$< on $(TARGET_NAME)") + +.PHONY: memory-replay +run-memory-replay: memory-replay run-memory-record + $(call run-test, $<, \ + $(QEMU) -monitor none -display none \ + -chardev file$(COMMA)path=$<.out$(COMMA)id=output \ + -icount shift=5$(COMMA)rr=replay$(COMMA)rrfile=record.bin \ + $(QEMU_OPTS) memory, \ + "$< on $(TARGET_NAME)") + +TESTS+=memory-record memory-replay diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target index e763dd9da3..509f1afa93 100644 --- a/tests/tcg/aarch64/Makefile.target +++ b/tests/tcg/aarch64/Makefile.target @@ -8,7 +8,7 @@ VPATH += $(ARM_SRC) AARCH64_SRC=$(SRC_PATH)/tests/tcg/aarch64 VPATH += $(AARCH64_SRC) -# we don't build any other ARM test +# Float-convert Tests AARCH64_TESTS=fcvt fcvt: LDFLAGS+=-lm @@ -17,7 +17,13 @@ run-fcvt: fcvt $(call run-test,$<,$(QEMU) $<, "$< on $(TARGET_NAME)") $(call diff-out,$<,$(AARCH64_SRC)/fcvt.ref) +# Pauth Tests AARCH64_TESTS += pauth-1 pauth-2 run-pauth-%: QEMU_OPTS += -cpu max +# Semihosting smoke test for linux-user +AARCH64_TESTS += semihosting +run-semihosting: semihosting + $(call run-test,$<,$(QEMU) $< 2> $<.err, "$< on $(TARGET_NAME)") + TESTS += $(AARCH64_TESTS) diff --git a/tests/tcg/aarch64/float_convs.ref b/tests/tcg/aarch64/float_convs.ref new file mode 100755 index 0000000000..23c062ae36 --- /dev/null +++ b/tests/tcg/aarch64/float_convs.ref @@ -0,0 +1,748 @@ +### Rounding to nearest +from single: f32(-nan:0xffa00000) + to double: f64(-nan:0x00fffc000000000000) (INVALID) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-nan:0xffc00000) + to double: f64(-nan:0x00fff8000000000000) (OK) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-inf:0xff800000) + to double: f64(-inf:0x00fff0000000000000) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + to double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + to double: f64(-0x1.1874b200000000000000p+103:0x00c661874b20000000) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + to double: f64(-0x1.c0bab600000000000000p+99:0x00c62c0bab60000000) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.31f75000000000000000p-40:0xab98fba8) + to double: f64(-0x1.31f75000000000000000p-40:0x00bd731f7500000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(-0x1.50544400000000000000p-66:0x9ea82a22) + to double: f64(-0x1.50544400000000000000p-66:0x00bbd5054440000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(-0x1.00000000000000000000p-126:0x80800000) + to double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x0.00000000000000000000p+0:0000000000) + to double: f64(0x0.00000000000000000000p+0:00000000000000000000) (OK) + to int32: 0 (OK) + to int64: 0 (OK) + to uint32: 0 (OK) + to uint64: 0 (OK) +from single: f32(0x1.00000000000000000000p-126:0x00800000) + to double: f64(0x1.00000000000000000000p-126:0x003810000000000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.00000000000000000000p-25:0x33000000) + to double: f64(0x1.00000000000000000000p-25:0x003e60000000000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) + to double: f64(0x1.ffffe600000000000000p-25:0x003e6ffffe60000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) + to double: f64(0x1.ff801a00000000000000p-15:0x003f0ff801a0000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.00000c00000000000000p-14:0x38800006) + to double: f64(0x1.00000c00000000000000p-14:0x003f100000c0000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.00000000000000000000p+0:0x3f800000) + to double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) (OK) + to int32: 1 (OK) + to int64: 1 (OK) + to uint32: 1 (OK) + to uint64: 1 (OK) +from single: f32(0x1.00400000000000000000p+0:0x3f802000) + to double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) (OK) + to int32: 1 (INEXACT ) + to int64: 1 (INEXACT ) + to uint32: 1 (INEXACT ) + to uint64: 1 (INEXACT ) +from single: f32(0x1.00000000000000000000p+1:0x40000000) + to double: f64(0x1.00000000000000000000p+1:0x004000000000000000) (OK) + to int32: 2 (OK) + to int64: 2 (OK) + to uint32: 2 (OK) + to uint64: 2 (OK) +from single: f32(0x1.5bf0a800000000000000p+1:0x402df854) + to double: f64(0x1.5bf0a800000000000000p+1:0x004005bf0a80000000) (OK) + to int32: 2 (INEXACT ) + to int64: 2 (INEXACT ) + to uint32: 2 (INEXACT ) + to uint64: 2 (INEXACT ) +from single: f32(0x1.921fb600000000000000p+1:0x40490fdb) + to double: f64(0x1.921fb600000000000000p+1:0x00400921fb60000000) (OK) + to int32: 3 (INEXACT ) + to int64: 3 (INEXACT ) + to uint32: 3 (INEXACT ) + to uint64: 3 (INEXACT ) +from single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + to double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) (OK) + to int32: 65503 (OK) + to int64: 65503 (OK) + to uint32: 65503 (OK) + to uint64: 65503 (OK) +from single: f32(0x1.ffc00000000000000000p+15:0x477fe000) + to double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) (OK) + to int32: 65504 (OK) + to int64: 65504 (OK) + to uint32: 65504 (OK) + to uint64: 65504 (OK) +from single: f32(0x1.ffc20000000000000000p+15:0x477fe100) + to double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) (OK) + to int32: 65505 (OK) + to int64: 65505 (OK) + to uint32: 65505 (OK) + to uint64: 65505 (OK) +from single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + to double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) (OK) + to int32: 131007 (OK) + to int64: 131007 (OK) + to uint32: 131007 (OK) + to uint64: 131007 (OK) +from single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) + to double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) (OK) + to int32: 131008 (OK) + to int64: 131008 (OK) + to uint32: 131008 (OK) + to uint64: 131008 (OK) +from single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) + to double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) (OK) + to int32: 131009 (OK) + to int64: 131009 (OK) + to uint32: 131009 (OK) + to uint64: 131009 (OK) +from single: f32(0x1.c0bab600000000000000p+99:0x71605d5b) + to double: f64(0x1.c0bab600000000000000p+99:0x00462c0bab60000000) (OK) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + to double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) (OK) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from single: f32(inf:0x7f800000) + to double: f64(inf:0x007ff0000000000000) (OK) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from single: f32(nan:0x7fc00000) + to double: f64(nan:0x007ff8000000000000) (OK) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(nan:0x7fa00000) + to double: f64(nan:0x007ffc000000000000) (INVALID) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +### Rounding upwards +from single: f32(-nan:0xffa00000) + to double: f64(-nan:0x00fffc000000000000) (INVALID) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-nan:0xffc00000) + to double: f64(-nan:0x00fff8000000000000) (OK) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-inf:0xff800000) + to double: f64(-inf:0x00fff0000000000000) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + to double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + to double: f64(-0x1.1874b200000000000000p+103:0x00c661874b20000000) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + to double: f64(-0x1.c0bab600000000000000p+99:0x00c62c0bab60000000) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.31f75000000000000000p-40:0xab98fba8) + to double: f64(-0x1.31f75000000000000000p-40:0x00bd731f7500000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(-0x1.50544400000000000000p-66:0x9ea82a22) + to double: f64(-0x1.50544400000000000000p-66:0x00bbd5054440000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(-0x1.00000000000000000000p-126:0x80800000) + to double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x0.00000000000000000000p+0:0000000000) + to double: f64(0x0.00000000000000000000p+0:00000000000000000000) (OK) + to int32: 0 (OK) + to int64: 0 (OK) + to uint32: 0 (OK) + to uint64: 0 (OK) +from single: f32(0x1.00000000000000000000p-126:0x00800000) + to double: f64(0x1.00000000000000000000p-126:0x003810000000000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.00000000000000000000p-25:0x33000000) + to double: f64(0x1.00000000000000000000p-25:0x003e60000000000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) + to double: f64(0x1.ffffe600000000000000p-25:0x003e6ffffe60000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) + to double: f64(0x1.ff801a00000000000000p-15:0x003f0ff801a0000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.00000c00000000000000p-14:0x38800006) + to double: f64(0x1.00000c00000000000000p-14:0x003f100000c0000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.00000000000000000000p+0:0x3f800000) + to double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) (OK) + to int32: 1 (OK) + to int64: 1 (OK) + to uint32: 1 (OK) + to uint64: 1 (OK) +from single: f32(0x1.00400000000000000000p+0:0x3f802000) + to double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) (OK) + to int32: 1 (INEXACT ) + to int64: 1 (INEXACT ) + to uint32: 1 (INEXACT ) + to uint64: 1 (INEXACT ) +from single: f32(0x1.00000000000000000000p+1:0x40000000) + to double: f64(0x1.00000000000000000000p+1:0x004000000000000000) (OK) + to int32: 2 (OK) + to int64: 2 (OK) + to uint32: 2 (OK) + to uint64: 2 (OK) +from single: f32(0x1.5bf0a800000000000000p+1:0x402df854) + to double: f64(0x1.5bf0a800000000000000p+1:0x004005bf0a80000000) (OK) + to int32: 2 (INEXACT ) + to int64: 2 (INEXACT ) + to uint32: 2 (INEXACT ) + to uint64: 2 (INEXACT ) +from single: f32(0x1.921fb600000000000000p+1:0x40490fdb) + to double: f64(0x1.921fb600000000000000p+1:0x00400921fb60000000) (OK) + to int32: 3 (INEXACT ) + to int64: 3 (INEXACT ) + to uint32: 3 (INEXACT ) + to uint64: 3 (INEXACT ) +from single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + to double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) (OK) + to int32: 65503 (OK) + to int64: 65503 (OK) + to uint32: 65503 (OK) + to uint64: 65503 (OK) +from single: f32(0x1.ffc00000000000000000p+15:0x477fe000) + to double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) (OK) + to int32: 65504 (OK) + to int64: 65504 (OK) + to uint32: 65504 (OK) + to uint64: 65504 (OK) +from single: f32(0x1.ffc20000000000000000p+15:0x477fe100) + to double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) (OK) + to int32: 65505 (OK) + to int64: 65505 (OK) + to uint32: 65505 (OK) + to uint64: 65505 (OK) +from single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + to double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) (OK) + to int32: 131007 (OK) + to int64: 131007 (OK) + to uint32: 131007 (OK) + to uint64: 131007 (OK) +from single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) + to double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) (OK) + to int32: 131008 (OK) + to int64: 131008 (OK) + to uint32: 131008 (OK) + to uint64: 131008 (OK) +from single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) + to double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) (OK) + to int32: 131009 (OK) + to int64: 131009 (OK) + to uint32: 131009 (OK) + to uint64: 131009 (OK) +from single: f32(0x1.c0bab600000000000000p+99:0x71605d5b) + to double: f64(0x1.c0bab600000000000000p+99:0x00462c0bab60000000) (OK) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + to double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) (OK) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from single: f32(inf:0x7f800000) + to double: f64(inf:0x007ff0000000000000) (OK) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from single: f32(nan:0x7fc00000) + to double: f64(nan:0x007ff8000000000000) (OK) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(nan:0x7fa00000) + to double: f64(nan:0x007ffc000000000000) (INVALID) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +### Rounding downwards +from single: f32(-nan:0xffa00000) + to double: f64(-nan:0x00fffc000000000000) (INVALID) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-nan:0xffc00000) + to double: f64(-nan:0x00fff8000000000000) (OK) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-inf:0xff800000) + to double: f64(-inf:0x00fff0000000000000) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + to double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + to double: f64(-0x1.1874b200000000000000p+103:0x00c661874b20000000) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + to double: f64(-0x1.c0bab600000000000000p+99:0x00c62c0bab60000000) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.31f75000000000000000p-40:0xab98fba8) + to double: f64(-0x1.31f75000000000000000p-40:0x00bd731f7500000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(-0x1.50544400000000000000p-66:0x9ea82a22) + to double: f64(-0x1.50544400000000000000p-66:0x00bbd5054440000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(-0x1.00000000000000000000p-126:0x80800000) + to double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x0.00000000000000000000p+0:0000000000) + to double: f64(0x0.00000000000000000000p+0:00000000000000000000) (OK) + to int32: 0 (OK) + to int64: 0 (OK) + to uint32: 0 (OK) + to uint64: 0 (OK) +from single: f32(0x1.00000000000000000000p-126:0x00800000) + to double: f64(0x1.00000000000000000000p-126:0x003810000000000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.00000000000000000000p-25:0x33000000) + to double: f64(0x1.00000000000000000000p-25:0x003e60000000000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) + to double: f64(0x1.ffffe600000000000000p-25:0x003e6ffffe60000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) + to double: f64(0x1.ff801a00000000000000p-15:0x003f0ff801a0000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.00000c00000000000000p-14:0x38800006) + to double: f64(0x1.00000c00000000000000p-14:0x003f100000c0000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.00000000000000000000p+0:0x3f800000) + to double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) (OK) + to int32: 1 (OK) + to int64: 1 (OK) + to uint32: 1 (OK) + to uint64: 1 (OK) +from single: f32(0x1.00400000000000000000p+0:0x3f802000) + to double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) (OK) + to int32: 1 (INEXACT ) + to int64: 1 (INEXACT ) + to uint32: 1 (INEXACT ) + to uint64: 1 (INEXACT ) +from single: f32(0x1.00000000000000000000p+1:0x40000000) + to double: f64(0x1.00000000000000000000p+1:0x004000000000000000) (OK) + to int32: 2 (OK) + to int64: 2 (OK) + to uint32: 2 (OK) + to uint64: 2 (OK) +from single: f32(0x1.5bf0a800000000000000p+1:0x402df854) + to double: f64(0x1.5bf0a800000000000000p+1:0x004005bf0a80000000) (OK) + to int32: 2 (INEXACT ) + to int64: 2 (INEXACT ) + to uint32: 2 (INEXACT ) + to uint64: 2 (INEXACT ) +from single: f32(0x1.921fb600000000000000p+1:0x40490fdb) + to double: f64(0x1.921fb600000000000000p+1:0x00400921fb60000000) (OK) + to int32: 3 (INEXACT ) + to int64: 3 (INEXACT ) + to uint32: 3 (INEXACT ) + to uint64: 3 (INEXACT ) +from single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + to double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) (OK) + to int32: 65503 (OK) + to int64: 65503 (OK) + to uint32: 65503 (OK) + to uint64: 65503 (OK) +from single: f32(0x1.ffc00000000000000000p+15:0x477fe000) + to double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) (OK) + to int32: 65504 (OK) + to int64: 65504 (OK) + to uint32: 65504 (OK) + to uint64: 65504 (OK) +from single: f32(0x1.ffc20000000000000000p+15:0x477fe100) + to double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) (OK) + to int32: 65505 (OK) + to int64: 65505 (OK) + to uint32: 65505 (OK) + to uint64: 65505 (OK) +from single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + to double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) (OK) + to int32: 131007 (OK) + to int64: 131007 (OK) + to uint32: 131007 (OK) + to uint64: 131007 (OK) +from single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) + to double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) (OK) + to int32: 131008 (OK) + to int64: 131008 (OK) + to uint32: 131008 (OK) + to uint64: 131008 (OK) +from single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) + to double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) (OK) + to int32: 131009 (OK) + to int64: 131009 (OK) + to uint32: 131009 (OK) + to uint64: 131009 (OK) +from single: f32(0x1.c0bab600000000000000p+99:0x71605d5b) + to double: f64(0x1.c0bab600000000000000p+99:0x00462c0bab60000000) (OK) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + to double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) (OK) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from single: f32(inf:0x7f800000) + to double: f64(inf:0x007ff0000000000000) (OK) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from single: f32(nan:0x7fc00000) + to double: f64(nan:0x007ff8000000000000) (OK) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(nan:0x7fa00000) + to double: f64(nan:0x007ffc000000000000) (INVALID) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +### Rounding to zero +from single: f32(-nan:0xffa00000) + to double: f64(-nan:0x00fffc000000000000) (INVALID) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-nan:0xffc00000) + to double: f64(-nan:0x00fff8000000000000) (OK) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-inf:0xff800000) + to double: f64(-inf:0x00fff0000000000000) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + to double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + to double: f64(-0x1.1874b200000000000000p+103:0x00c661874b20000000) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + to double: f64(-0x1.c0bab600000000000000p+99:0x00c62c0bab60000000) (OK) + to int32: -2147483648 (INVALID) + to int64: -9223372036854775808 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.31f75000000000000000p-40:0xab98fba8) + to double: f64(-0x1.31f75000000000000000p-40:0x00bd731f7500000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(-0x1.50544400000000000000p-66:0x9ea82a22) + to double: f64(-0x1.50544400000000000000p-66:0x00bbd5054440000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(-0x1.00000000000000000000p-126:0x80800000) + to double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x0.00000000000000000000p+0:0000000000) + to double: f64(0x0.00000000000000000000p+0:00000000000000000000) (OK) + to int32: 0 (OK) + to int64: 0 (OK) + to uint32: 0 (OK) + to uint64: 0 (OK) +from single: f32(0x1.00000000000000000000p-126:0x00800000) + to double: f64(0x1.00000000000000000000p-126:0x003810000000000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.00000000000000000000p-25:0x33000000) + to double: f64(0x1.00000000000000000000p-25:0x003e60000000000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) + to double: f64(0x1.ffffe600000000000000p-25:0x003e6ffffe60000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) + to double: f64(0x1.ff801a00000000000000p-15:0x003f0ff801a0000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.00000c00000000000000p-14:0x38800006) + to double: f64(0x1.00000c00000000000000p-14:0x003f100000c0000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.00000000000000000000p+0:0x3f800000) + to double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) (OK) + to int32: 1 (OK) + to int64: 1 (OK) + to uint32: 1 (OK) + to uint64: 1 (OK) +from single: f32(0x1.00400000000000000000p+0:0x3f802000) + to double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) (OK) + to int32: 1 (INEXACT ) + to int64: 1 (INEXACT ) + to uint32: 1 (INEXACT ) + to uint64: 1 (INEXACT ) +from single: f32(0x1.00000000000000000000p+1:0x40000000) + to double: f64(0x1.00000000000000000000p+1:0x004000000000000000) (OK) + to int32: 2 (OK) + to int64: 2 (OK) + to uint32: 2 (OK) + to uint64: 2 (OK) +from single: f32(0x1.5bf0a800000000000000p+1:0x402df854) + to double: f64(0x1.5bf0a800000000000000p+1:0x004005bf0a80000000) (OK) + to int32: 2 (INEXACT ) + to int64: 2 (INEXACT ) + to uint32: 2 (INEXACT ) + to uint64: 2 (INEXACT ) +from single: f32(0x1.921fb600000000000000p+1:0x40490fdb) + to double: f64(0x1.921fb600000000000000p+1:0x00400921fb60000000) (OK) + to int32: 3 (INEXACT ) + to int64: 3 (INEXACT ) + to uint32: 3 (INEXACT ) + to uint64: 3 (INEXACT ) +from single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + to double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) (OK) + to int32: 65503 (OK) + to int64: 65503 (OK) + to uint32: 65503 (OK) + to uint64: 65503 (OK) +from single: f32(0x1.ffc00000000000000000p+15:0x477fe000) + to double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) (OK) + to int32: 65504 (OK) + to int64: 65504 (OK) + to uint32: 65504 (OK) + to uint64: 65504 (OK) +from single: f32(0x1.ffc20000000000000000p+15:0x477fe100) + to double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) (OK) + to int32: 65505 (OK) + to int64: 65505 (OK) + to uint32: 65505 (OK) + to uint64: 65505 (OK) +from single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + to double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) (OK) + to int32: 131007 (OK) + to int64: 131007 (OK) + to uint32: 131007 (OK) + to uint64: 131007 (OK) +from single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) + to double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) (OK) + to int32: 131008 (OK) + to int64: 131008 (OK) + to uint32: 131008 (OK) + to uint64: 131008 (OK) +from single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) + to double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) (OK) + to int32: 131009 (OK) + to int64: 131009 (OK) + to uint32: 131009 (OK) + to uint64: 131009 (OK) +from single: f32(0x1.c0bab600000000000000p+99:0x71605d5b) + to double: f64(0x1.c0bab600000000000000p+99:0x00462c0bab60000000) (OK) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + to double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) (OK) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from single: f32(inf:0x7f800000) + to double: f64(inf:0x007ff0000000000000) (OK) + to int32: 2147483647 (INVALID) + to int64: 9223372036854775807 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from single: f32(nan:0x7fc00000) + to double: f64(nan:0x007ff8000000000000) (OK) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(nan:0x7fa00000) + to double: f64(nan:0x007ffc000000000000) (INVALID) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) diff --git a/tests/tcg/aarch64/float_madds.ref b/tests/tcg/aarch64/float_madds.ref new file mode 100644 index 0000000000..21c0539887 --- /dev/null +++ b/tests/tcg/aarch64/float_madds.ref @@ -0,0 +1,768 @@ +### Rounding to nearest +op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) +res: f32(-nan:0xffe00000) flags=INVALID (0/0) +op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-nan:0xffa00000) +res: f32(-nan:0xffe00000) flags=INVALID (0/1) +op : f32(-inf:0xff800000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) +res: f32(-nan:0xffe00000) flags=INVALID (0/2) +op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) +res: f32(-nan:0xffc00000) flags=OK (1/0) +op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-nan:0xffc00000) +res: f32(-nan:0xffc00000) flags=OK (1/1) +op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) +res: f32(-nan:0xffc00000) flags=OK (1/2) +op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) +res: f32(inf:0x7f800000) flags=OK (2/0) +op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-inf:0xff800000) +res: f32(-inf:0xff800000) flags=OK (2/1) +op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) +res: f32(inf:0x7f800000) flags=OK (2/2) +op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/0) +op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/1) +op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/2) +op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (4/0) +op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) +res: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) flags=INEXACT (4/1) +op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) +res: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) flags=INEXACT (4/2) +op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) +res: f32(0x1.0c27fa00000000000000p+60:0x5d8613fd) flags=INEXACT (5/0) +op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) +res: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) flags=INEXACT (5/1) +op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) +res: f32(0x1.26c46200000000000000p+34:0x50936231) flags=INEXACT (5/2) +op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) +res: f32(0x1.91f94000000000000000p-106:0x0ac8fca0) flags=INEXACT (6/0) +op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) +res: f32(-0x1.31f75000000000000000p-40:0xab98fba8) flags=INEXACT (6/1) +op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) +res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=INEXACT (6/2) +op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (7/0) +op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) +res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=OK (7/1) +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) +res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (7/2) +op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) +res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (8/0) +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(-0x1.00000000000000000000p-126:0x80800000) +res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (8/1) +op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(-0x0.00000000000000000000p+0:0x80000000) flags=UNDERFLOW INEXACT (8/2) +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) +res: f32(0x1.00000000000000000000p-25:0x33000000) flags=OK (9/0) +op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (9/1) +op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) +res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (9/2) +op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) +res: f32(0x1.ffffe600000000000000p-25:0x337ffff3) flags=INEXACT (10/0) +op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.00000000000000000000p-126:0x00800000) +res: f32(0x1.ffffe600000000000000p-50:0x26fffff3) flags=INEXACT (10/1) +op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) +res: f32(0x1.00000000000000000000p-25:0x33000000) flags=INEXACT (10/2) +op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) +res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (11/0) +op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000000000000000000p-25:0x33000000) +res: f32(0x1.0007fe00000000000000p-25:0x330003ff) flags=INEXACT (11/1) +op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) +res: f32(0x1.0001f200000000000000p-24:0x338000f9) flags=INEXACT (11/2) +op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) +res: f32(0x1.00000c00000000000000p-14:0x38800006) flags=INEXACT (12/0) +op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) +res: f32(0x1.0ffbf400000000000000p-24:0x3387fdfa) flags=INEXACT (12/1) +op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) +res: f32(0x1.ff801c00000000000000p-15:0x387fc00e) flags=INEXACT (12/2) +op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) +res: f32(0x1.00000000000000000000p+0:0x3f800000) flags=INEXACT (13/0) +op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) +res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/1) +op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) +res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/2) +op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) +res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/0) +op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000c00000000000000p-14:0x38800006) +res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/1) +op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) +res: f32(0x1.00040200000000000000p+0:0x3f800201) flags=INEXACT (14/2) +op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) +res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/0) +op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.00000000000000000000p+0:0x3f800000) +res: f32(0x1.80400000000000000000p+1:0x40402000) flags=OK (15/1) +op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) +res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/2) +op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) +res: f32(0x1.2e185400000000000000p+2:0x40970c2a) flags=OK (16/0) +op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.00400000000000000000p+0:0x3f802000) +res: f32(0x1.9c00a800000000000000p+2:0x40ce0054) flags=OK (16/1) +op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) +res: f32(0x1.2e23d200000000000000p+2:0x409711e9) flags=INEXACT (16/2) +op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) +res: f32(0x1.12804200000000000000p+3:0x41094021) flags=INEXACT (17/0) +op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.00000000000000000000p+1:0x40000000) +res: f32(0x1.51458000000000000000p+3:0x4128a2c0) flags=INEXACT (17/1) +op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) +res: f32(0x1.200c0400000000000000p+3:0x41100602) flags=INEXACT (17/2) +op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) +res: f32(0x1.ffcf1400000000000000p+15:0x477fe78a) flags=INEXACT (18/0) +op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.5bf0a800000000000000p+1:0x402df854) +res: f32(0x1.91ed3c00000000000000p+17:0x4848f69e) flags=INEXACT (18/1) +op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) +res: f32(0x1.5bc56000000000000000p+17:0x482de2b0) flags=INEXACT (18/2) +op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) +res: f32(0x1.08edf000000000000000p+18:0x488476f8) flags=INEXACT (19/0) +op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.921fb600000000000000p+1:0x40490fdb) +res: f32(0x1.ff7e0800000000000000p+31:0x4f7fbf04) flags=INEXACT (19/1) +op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) +res: f32(0x1.08ee7a00000000000000p+18:0x4884773d) flags=INEXACT (19/2) +op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) +res: f32(0x1.ff800800000000000000p+31:0x4f7fc004) flags=INEXACT (20/0) +op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) +res: f32(0x1.ff840800000000000000p+31:0x4f7fc204) flags=INEXACT (20/1) +op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) +res: f32(0x1.ff820800000000000000p+31:0x4f7fc104) flags=INEXACT (20/2) +op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) +res: f32(0x1.ff860800000000000000p+31:0x4f7fc304) flags=INEXACT (21/0) +op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+15:0x477fe000) +res: f32(0x1.ff820800000000000000p+32:0x4fffc104) flags=INEXACT (21/1) +op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) +res: f32(0x1.ff800800000000000000p+32:0x4fffc004) flags=INEXACT (21/2) +op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) +res: f32(0x1.ff830800000000000000p+32:0x4fffc184) flags=INEXACT (22/0) +op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) +res: f32(0x1.ff7f8800000000000000p+33:0x507fbfc4) flags=INEXACT (22/1) +op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) +res: f32(0x1.ff840800000000000000p+32:0x4fffc204) flags=INEXACT (22/2) +op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) +res: f32(0x1.ff800800000000000000p+33:0x507fc004) flags=INEXACT (23/0) +op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) +res: f32(0x1.ff820800000000000000p+33:0x507fc104) flags=INEXACT (23/1) +op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) +res: f32(0x1.ff810800000000000000p+33:0x507fc084) flags=INEXACT (23/2) +op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) +res: f32(0x1.c0bab600000000000000p+99:0x71605d5b) flags=INEXACT (24/0) +op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) +res: f32(0x1.c0838000000000000000p+116:0x79e041c0) flags=INEXACT (24/1) +op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) +res: f32(0x1.c0829e00000000000000p+116:0x79e0414f) flags=INEXACT (24/2) +op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/0) +op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/1) +op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/2) +op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) +res: f32(inf:0x7f800000) flags=OK (26/0) +op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) +res: f32(inf:0x7f800000) flags=OK (26/1) +op : f32(inf:0x7f800000) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) +res: f32(inf:0x7f800000) flags=OK (26/2) +op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) +res: f32(nan:0x7fc00000) flags=OK (27/0) +op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) +res: f32(nan:0x7fc00000) flags=OK (27/1) +op : f32(nan:0x7fc00000) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) +res: f32(nan:0x7fc00000) flags=OK (27/2) +op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) +res: f32(nan:0x7fe00000) flags=INVALID (28/0) +op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(inf:0x7f800000) +res: f32(nan:0x7fe00000) flags=INVALID (28/1) +op : f32(nan:0x7fa00000) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) +res: f32(nan:0x7fe00000) flags=INVALID (28/2) +op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) +res: f32(-nan:0xffe00000) flags=INVALID (29/0) +op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(nan:0x7fc00000) +res: f32(nan:0x7fe00000) flags=INVALID (29/1) +op : f32(-nan:0xffa00000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) +res: f32(nan:0x7fe00000) flags=INVALID (29/2) +op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) +res: f32(nan:0x7fe00000) flags=INVALID (30/0) +op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(nan:0x7fa00000) +res: f32(nan:0x7fe00000) flags=INVALID (30/1) +op : f32(-nan:0xffc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) +res: f32(-nan:0xffe00000) flags=INVALID (30/2) +# LP184149 +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-1:0x3f000000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(0x0.00000000000000000000p+0:0000000000) flags=OK (31/0) +op : f32(0x1.00000000000000000000p-149:0x00000001) * f32(0x1.00000000000000000000p-149:0x00000001) + f32(0x1.00000000000000000000p-149:0x00000001) +res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (32/0) +### Rounding upwards +op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) +res: f32(-nan:0xffe00000) flags=INVALID (0/0) +op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-nan:0xffa00000) +res: f32(-nan:0xffe00000) flags=INVALID (0/1) +op : f32(-inf:0xff800000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) +res: f32(-nan:0xffe00000) flags=INVALID (0/2) +op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) +res: f32(-nan:0xffc00000) flags=OK (1/0) +op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-nan:0xffc00000) +res: f32(-nan:0xffc00000) flags=OK (1/1) +op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) +res: f32(-nan:0xffc00000) flags=OK (1/2) +op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) +res: f32(inf:0x7f800000) flags=OK (2/0) +op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-inf:0xff800000) +res: f32(-inf:0xff800000) flags=OK (2/1) +op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) +res: f32(inf:0x7f800000) flags=OK (2/2) +op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/0) +op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/1) +op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/2) +op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (4/0) +op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) +res: f32(-0x1.1874b000000000000000p+103:0xf30c3a58) flags=INEXACT (4/1) +op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) +res: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) flags=INEXACT (4/2) +op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) +res: f32(0x1.0c27fa00000000000000p+60:0x5d8613fd) flags=INEXACT (5/0) +op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) +res: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) flags=INEXACT (5/1) +op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) +res: f32(0x1.26c46200000000000000p+34:0x50936231) flags=INEXACT (5/2) +op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) +res: f32(0x1.91f94000000000000000p-106:0x0ac8fca0) flags=INEXACT (6/0) +op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) +res: f32(-0x1.31f74e00000000000000p-40:0xab98fba7) flags=INEXACT (6/1) +op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) +res: f32(-0x1.50544200000000000000p-66:0x9ea82a21) flags=INEXACT (6/2) +op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (7/0) +op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) +res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=OK (7/1) +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) +res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (7/2) +op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) +res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (8/0) +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(-0x1.00000000000000000000p-126:0x80800000) +res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (8/1) +op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(-0x0.00000000000000000000p+0:0x80000000) flags=UNDERFLOW INEXACT (8/2) +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) +res: f32(0x1.00000000000000000000p-25:0x33000000) flags=OK (9/0) +op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (9/1) +op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) +res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (9/2) +op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) +res: f32(0x1.ffffe800000000000000p-25:0x337ffff4) flags=INEXACT (10/0) +op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.00000000000000000000p-126:0x00800000) +res: f32(0x1.ffffe800000000000000p-50:0x26fffff4) flags=INEXACT (10/1) +op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) +res: f32(0x1.00000200000000000000p-25:0x33000001) flags=INEXACT (10/2) +op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) +res: f32(0x1.ff801c00000000000000p-15:0x387fc00e) flags=INEXACT (11/0) +op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000000000000000000p-25:0x33000000) +res: f32(0x1.00080000000000000000p-25:0x33000400) flags=INEXACT (11/1) +op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) +res: f32(0x1.0001f400000000000000p-24:0x338000fa) flags=INEXACT (11/2) +op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) +res: f32(0x1.00000e00000000000000p-14:0x38800007) flags=INEXACT (12/0) +op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) +res: f32(0x1.0ffbf600000000000000p-24:0x3387fdfb) flags=INEXACT (12/1) +op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) +res: f32(0x1.ff801c00000000000000p-15:0x387fc00e) flags=INEXACT (12/2) +op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) +res: f32(0x1.00000200000000000000p+0:0x3f800001) flags=INEXACT (13/0) +op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) +res: f32(0x1.ffc01a00000000000000p-14:0x38ffe00d) flags=INEXACT (13/1) +op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) +res: f32(0x1.ffc01a00000000000000p-14:0x38ffe00d) flags=INEXACT (13/2) +op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) +res: f32(0x1.00440200000000000000p+0:0x3f802201) flags=INEXACT (14/0) +op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000c00000000000000p-14:0x38800006) +res: f32(0x1.00440200000000000000p+0:0x3f802201) flags=INEXACT (14/1) +op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) +res: f32(0x1.00040200000000000000p+0:0x3f800201) flags=INEXACT (14/2) +op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) +res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/0) +op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.00000000000000000000p+0:0x3f800000) +res: f32(0x1.80400000000000000000p+1:0x40402000) flags=OK (15/1) +op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) +res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/2) +op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) +res: f32(0x1.2e185400000000000000p+2:0x40970c2a) flags=OK (16/0) +op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.00400000000000000000p+0:0x3f802000) +res: f32(0x1.9c00a800000000000000p+2:0x40ce0054) flags=OK (16/1) +op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) +res: f32(0x1.2e23d400000000000000p+2:0x409711ea) flags=INEXACT (16/2) +op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) +res: f32(0x1.12804200000000000000p+3:0x41094021) flags=INEXACT (17/0) +op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.00000000000000000000p+1:0x40000000) +res: f32(0x1.51458200000000000000p+3:0x4128a2c1) flags=INEXACT (17/1) +op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) +res: f32(0x1.200c0600000000000000p+3:0x41100603) flags=INEXACT (17/2) +op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) +res: f32(0x1.ffcf1600000000000000p+15:0x477fe78b) flags=INEXACT (18/0) +op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.5bf0a800000000000000p+1:0x402df854) +res: f32(0x1.91ed3c00000000000000p+17:0x4848f69e) flags=INEXACT (18/1) +op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) +res: f32(0x1.5bc56200000000000000p+17:0x482de2b1) flags=INEXACT (18/2) +op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) +res: f32(0x1.08edf000000000000000p+18:0x488476f8) flags=INEXACT (19/0) +op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.921fb600000000000000p+1:0x40490fdb) +res: f32(0x1.ff7e0a00000000000000p+31:0x4f7fbf05) flags=INEXACT (19/1) +op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) +res: f32(0x1.08ee7a00000000000000p+18:0x4884773d) flags=INEXACT (19/2) +op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) +res: f32(0x1.ff800a00000000000000p+31:0x4f7fc005) flags=INEXACT (20/0) +op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) +res: f32(0x1.ff840800000000000000p+31:0x4f7fc204) flags=INEXACT (20/1) +op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) +res: f32(0x1.ff820800000000000000p+31:0x4f7fc104) flags=INEXACT (20/2) +op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) +res: f32(0x1.ff860800000000000000p+31:0x4f7fc304) flags=INEXACT (21/0) +op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+15:0x477fe000) +res: f32(0x1.ff820800000000000000p+32:0x4fffc104) flags=INEXACT (21/1) +op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) +res: f32(0x1.ff800a00000000000000p+32:0x4fffc005) flags=INEXACT (21/2) +op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) +res: f32(0x1.ff830800000000000000p+32:0x4fffc184) flags=INEXACT (22/0) +op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) +res: f32(0x1.ff7f8a00000000000000p+33:0x507fbfc5) flags=INEXACT (22/1) +op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) +res: f32(0x1.ff840800000000000000p+32:0x4fffc204) flags=INEXACT (22/2) +op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) +res: f32(0x1.ff800a00000000000000p+33:0x507fc005) flags=INEXACT (23/0) +op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) +res: f32(0x1.ff820800000000000000p+33:0x507fc104) flags=INEXACT (23/1) +op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) +res: f32(0x1.ff810800000000000000p+33:0x507fc084) flags=INEXACT (23/2) +op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) +res: f32(0x1.c0bab800000000000000p+99:0x71605d5c) flags=INEXACT (24/0) +op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) +res: f32(0x1.c0838000000000000000p+116:0x79e041c0) flags=INEXACT (24/1) +op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) +res: f32(0x1.c082a000000000000000p+116:0x79e04150) flags=INEXACT (24/2) +op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/0) +op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/1) +op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/2) +op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) +res: f32(inf:0x7f800000) flags=OK (26/0) +op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) +res: f32(inf:0x7f800000) flags=OK (26/1) +op : f32(inf:0x7f800000) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) +res: f32(inf:0x7f800000) flags=OK (26/2) +op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) +res: f32(nan:0x7fc00000) flags=OK (27/0) +op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) +res: f32(nan:0x7fc00000) flags=OK (27/1) +op : f32(nan:0x7fc00000) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) +res: f32(nan:0x7fc00000) flags=OK (27/2) +op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) +res: f32(nan:0x7fe00000) flags=INVALID (28/0) +op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(inf:0x7f800000) +res: f32(nan:0x7fe00000) flags=INVALID (28/1) +op : f32(nan:0x7fa00000) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) +res: f32(nan:0x7fe00000) flags=INVALID (28/2) +op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) +res: f32(-nan:0xffe00000) flags=INVALID (29/0) +op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(nan:0x7fc00000) +res: f32(nan:0x7fe00000) flags=INVALID (29/1) +op : f32(-nan:0xffa00000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) +res: f32(nan:0x7fe00000) flags=INVALID (29/2) +op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) +res: f32(nan:0x7fe00000) flags=INVALID (30/0) +op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(nan:0x7fa00000) +res: f32(nan:0x7fe00000) flags=INVALID (30/1) +op : f32(-nan:0xffc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) +res: f32(-nan:0xffe00000) flags=INVALID (30/2) +# LP184149 +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-1:0x3f000000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(0x0.00000000000000000000p+0:0000000000) flags=OK (31/0) +op : f32(0x1.00000000000000000000p-149:0x00000001) * f32(0x1.00000000000000000000p-149:0x00000001) + f32(0x1.00000000000000000000p-149:0x00000001) +res: f32(0x1.00000000000000000000p-148:0x00000002) flags=UNDERFLOW INEXACT (32/0) +### Rounding downwards +op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) +res: f32(-nan:0xffe00000) flags=INVALID (0/0) +op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-nan:0xffa00000) +res: f32(-nan:0xffe00000) flags=INVALID (0/1) +op : f32(-inf:0xff800000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) +res: f32(-nan:0xffe00000) flags=INVALID (0/2) +op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) +res: f32(-nan:0xffc00000) flags=OK (1/0) +op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-nan:0xffc00000) +res: f32(-nan:0xffc00000) flags=OK (1/1) +op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) +res: f32(-nan:0xffc00000) flags=OK (1/2) +op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) +res: f32(inf:0x7f800000) flags=OK (2/0) +op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-inf:0xff800000) +res: f32(-inf:0xff800000) flags=OK (2/1) +op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) +res: f32(inf:0x7f800000) flags=OK (2/2) +op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/0) +op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/1) +op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/2) +op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (4/0) +op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) +res: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) flags=INEXACT (4/1) +op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) +res: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) flags=INEXACT (4/2) +op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) +res: f32(0x1.0c27f800000000000000p+60:0x5d8613fc) flags=INEXACT (5/0) +op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) +res: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) flags=INEXACT (5/1) +op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) +res: f32(0x1.26c46000000000000000p+34:0x50936230) flags=INEXACT (5/2) +op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) +res: f32(0x1.91f93e00000000000000p-106:0x0ac8fc9f) flags=INEXACT (6/0) +op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) +res: f32(-0x1.31f75000000000000000p-40:0xab98fba8) flags=INEXACT (6/1) +op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) +res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=INEXACT (6/2) +op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (7/0) +op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) +res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=OK (7/1) +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) +res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (7/2) +op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) +res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (8/0) +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(-0x1.00000000000000000000p-126:0x80800000) +res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (8/1) +op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(-0x1.00000000000000000000p-149:0x80000001) flags=UNDERFLOW INEXACT (8/2) +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) +res: f32(0x1.00000000000000000000p-25:0x33000000) flags=OK (9/0) +op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (9/1) +op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) +res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (9/2) +op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) +res: f32(0x1.ffffe600000000000000p-25:0x337ffff3) flags=INEXACT (10/0) +op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.00000000000000000000p-126:0x00800000) +res: f32(0x1.ffffe600000000000000p-50:0x26fffff3) flags=INEXACT (10/1) +op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) +res: f32(0x1.00000000000000000000p-25:0x33000000) flags=INEXACT (10/2) +op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) +res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (11/0) +op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000000000000000000p-25:0x33000000) +res: f32(0x1.0007fe00000000000000p-25:0x330003ff) flags=INEXACT (11/1) +op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) +res: f32(0x1.0001f200000000000000p-24:0x338000f9) flags=INEXACT (11/2) +op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) +res: f32(0x1.00000c00000000000000p-14:0x38800006) flags=INEXACT (12/0) +op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) +res: f32(0x1.0ffbf400000000000000p-24:0x3387fdfa) flags=INEXACT (12/1) +op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) +res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (12/2) +op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) +res: f32(0x1.00000000000000000000p+0:0x3f800000) flags=INEXACT (13/0) +op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) +res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/1) +op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) +res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/2) +op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) +res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/0) +op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000c00000000000000p-14:0x38800006) +res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/1) +op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) +res: f32(0x1.00040000000000000000p+0:0x3f800200) flags=INEXACT (14/2) +op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) +res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/0) +op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.00000000000000000000p+0:0x3f800000) +res: f32(0x1.80400000000000000000p+1:0x40402000) flags=OK (15/1) +op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) +res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/2) +op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) +res: f32(0x1.2e185400000000000000p+2:0x40970c2a) flags=OK (16/0) +op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.00400000000000000000p+0:0x3f802000) +res: f32(0x1.9c00a800000000000000p+2:0x40ce0054) flags=OK (16/1) +op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) +res: f32(0x1.2e23d200000000000000p+2:0x409711e9) flags=INEXACT (16/2) +op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) +res: f32(0x1.12804000000000000000p+3:0x41094020) flags=INEXACT (17/0) +op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.00000000000000000000p+1:0x40000000) +res: f32(0x1.51458000000000000000p+3:0x4128a2c0) flags=INEXACT (17/1) +op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) +res: f32(0x1.200c0400000000000000p+3:0x41100602) flags=INEXACT (17/2) +op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) +res: f32(0x1.ffcf1400000000000000p+15:0x477fe78a) flags=INEXACT (18/0) +op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.5bf0a800000000000000p+1:0x402df854) +res: f32(0x1.91ed3a00000000000000p+17:0x4848f69d) flags=INEXACT (18/1) +op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) +res: f32(0x1.5bc56000000000000000p+17:0x482de2b0) flags=INEXACT (18/2) +op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) +res: f32(0x1.08edee00000000000000p+18:0x488476f7) flags=INEXACT (19/0) +op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.921fb600000000000000p+1:0x40490fdb) +res: f32(0x1.ff7e0800000000000000p+31:0x4f7fbf04) flags=INEXACT (19/1) +op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) +res: f32(0x1.08ee7800000000000000p+18:0x4884773c) flags=INEXACT (19/2) +op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) +res: f32(0x1.ff800800000000000000p+31:0x4f7fc004) flags=INEXACT (20/0) +op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) +res: f32(0x1.ff840600000000000000p+31:0x4f7fc203) flags=INEXACT (20/1) +op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) +res: f32(0x1.ff820600000000000000p+31:0x4f7fc103) flags=INEXACT (20/2) +op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) +res: f32(0x1.ff860600000000000000p+31:0x4f7fc303) flags=INEXACT (21/0) +op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+15:0x477fe000) +res: f32(0x1.ff820600000000000000p+32:0x4fffc103) flags=INEXACT (21/1) +op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) +res: f32(0x1.ff800800000000000000p+32:0x4fffc004) flags=INEXACT (21/2) +op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) +res: f32(0x1.ff830600000000000000p+32:0x4fffc183) flags=INEXACT (22/0) +op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) +res: f32(0x1.ff7f8800000000000000p+33:0x507fbfc4) flags=INEXACT (22/1) +op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) +res: f32(0x1.ff840600000000000000p+32:0x4fffc203) flags=INEXACT (22/2) +op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) +res: f32(0x1.ff800800000000000000p+33:0x507fc004) flags=INEXACT (23/0) +op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) +res: f32(0x1.ff820600000000000000p+33:0x507fc103) flags=INEXACT (23/1) +op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) +res: f32(0x1.ff810600000000000000p+33:0x507fc083) flags=INEXACT (23/2) +op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) +res: f32(0x1.c0bab600000000000000p+99:0x71605d5b) flags=INEXACT (24/0) +op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) +res: f32(0x1.c0837e00000000000000p+116:0x79e041bf) flags=INEXACT (24/1) +op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) +res: f32(0x1.c0829e00000000000000p+116:0x79e0414f) flags=INEXACT (24/2) +op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/0) +op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/1) +op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/2) +op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) +res: f32(inf:0x7f800000) flags=OK (26/0) +op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) +res: f32(inf:0x7f800000) flags=OK (26/1) +op : f32(inf:0x7f800000) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) +res: f32(inf:0x7f800000) flags=OK (26/2) +op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) +res: f32(nan:0x7fc00000) flags=OK (27/0) +op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) +res: f32(nan:0x7fc00000) flags=OK (27/1) +op : f32(nan:0x7fc00000) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) +res: f32(nan:0x7fc00000) flags=OK (27/2) +op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) +res: f32(nan:0x7fe00000) flags=INVALID (28/0) +op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(inf:0x7f800000) +res: f32(nan:0x7fe00000) flags=INVALID (28/1) +op : f32(nan:0x7fa00000) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) +res: f32(nan:0x7fe00000) flags=INVALID (28/2) +op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) +res: f32(-nan:0xffe00000) flags=INVALID (29/0) +op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(nan:0x7fc00000) +res: f32(nan:0x7fe00000) flags=INVALID (29/1) +op : f32(-nan:0xffa00000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) +res: f32(nan:0x7fe00000) flags=INVALID (29/2) +op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) +res: f32(nan:0x7fe00000) flags=INVALID (30/0) +op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(nan:0x7fa00000) +res: f32(nan:0x7fe00000) flags=INVALID (30/1) +op : f32(-nan:0xffc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) +res: f32(-nan:0xffe00000) flags=INVALID (30/2) +# LP184149 +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-1:0x3f000000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(0x0.00000000000000000000p+0:0000000000) flags=OK (31/0) +op : f32(0x1.00000000000000000000p-149:0x00000001) * f32(0x1.00000000000000000000p-149:0x00000001) + f32(0x1.00000000000000000000p-149:0x00000001) +res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (32/0) +### Rounding to zero +op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) +res: f32(-nan:0xffe00000) flags=INVALID (0/0) +op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-nan:0xffa00000) +res: f32(-nan:0xffe00000) flags=INVALID (0/1) +op : f32(-inf:0xff800000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) +res: f32(-nan:0xffe00000) flags=INVALID (0/2) +op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) +res: f32(-nan:0xffc00000) flags=OK (1/0) +op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-nan:0xffc00000) +res: f32(-nan:0xffc00000) flags=OK (1/1) +op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) +res: f32(-nan:0xffc00000) flags=OK (1/2) +op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) +res: f32(inf:0x7f800000) flags=OK (2/0) +op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-inf:0xff800000) +res: f32(-inf:0xff800000) flags=OK (2/1) +op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) +res: f32(inf:0x7f800000) flags=OK (2/2) +op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/0) +op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/1) +op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/2) +op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (4/0) +op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) +res: f32(-0x1.1874b000000000000000p+103:0xf30c3a58) flags=INEXACT (4/1) +op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) +res: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) flags=INEXACT (4/2) +op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) +res: f32(0x1.0c27f800000000000000p+60:0x5d8613fc) flags=INEXACT (5/0) +op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) +res: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) flags=INEXACT (5/1) +op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) +res: f32(0x1.26c46000000000000000p+34:0x50936230) flags=INEXACT (5/2) +op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) +res: f32(0x1.91f93e00000000000000p-106:0x0ac8fc9f) flags=INEXACT (6/0) +op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) +res: f32(-0x1.31f74e00000000000000p-40:0xab98fba7) flags=INEXACT (6/1) +op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) +res: f32(-0x1.50544200000000000000p-66:0x9ea82a21) flags=INEXACT (6/2) +op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (7/0) +op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) +res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=OK (7/1) +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) +res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (7/2) +op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) +res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (8/0) +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(-0x1.00000000000000000000p-126:0x80800000) +res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (8/1) +op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(-0x0.00000000000000000000p+0:0x80000000) flags=UNDERFLOW INEXACT (8/2) +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) +res: f32(0x1.00000000000000000000p-25:0x33000000) flags=OK (9/0) +op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (9/1) +op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) +res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (9/2) +op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) +res: f32(0x1.ffffe600000000000000p-25:0x337ffff3) flags=INEXACT (10/0) +op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.00000000000000000000p-126:0x00800000) +res: f32(0x1.ffffe600000000000000p-50:0x26fffff3) flags=INEXACT (10/1) +op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) +res: f32(0x1.00000000000000000000p-25:0x33000000) flags=INEXACT (10/2) +op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) +res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (11/0) +op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000000000000000000p-25:0x33000000) +res: f32(0x1.0007fe00000000000000p-25:0x330003ff) flags=INEXACT (11/1) +op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) +res: f32(0x1.0001f200000000000000p-24:0x338000f9) flags=INEXACT (11/2) +op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) +res: f32(0x1.00000c00000000000000p-14:0x38800006) flags=INEXACT (12/0) +op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) +res: f32(0x1.0ffbf400000000000000p-24:0x3387fdfa) flags=INEXACT (12/1) +op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) +res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (12/2) +op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) +res: f32(0x1.00000000000000000000p+0:0x3f800000) flags=INEXACT (13/0) +op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) +res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/1) +op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) +res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/2) +op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) +res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/0) +op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000c00000000000000p-14:0x38800006) +res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/1) +op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) +res: f32(0x1.00040000000000000000p+0:0x3f800200) flags=INEXACT (14/2) +op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) +res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/0) +op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.00000000000000000000p+0:0x3f800000) +res: f32(0x1.80400000000000000000p+1:0x40402000) flags=OK (15/1) +op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) +res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/2) +op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) +res: f32(0x1.2e185400000000000000p+2:0x40970c2a) flags=OK (16/0) +op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.00400000000000000000p+0:0x3f802000) +res: f32(0x1.9c00a800000000000000p+2:0x40ce0054) flags=OK (16/1) +op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) +res: f32(0x1.2e23d200000000000000p+2:0x409711e9) flags=INEXACT (16/2) +op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) +res: f32(0x1.12804000000000000000p+3:0x41094020) flags=INEXACT (17/0) +op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.00000000000000000000p+1:0x40000000) +res: f32(0x1.51458000000000000000p+3:0x4128a2c0) flags=INEXACT (17/1) +op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) +res: f32(0x1.200c0400000000000000p+3:0x41100602) flags=INEXACT (17/2) +op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) +res: f32(0x1.ffcf1400000000000000p+15:0x477fe78a) flags=INEXACT (18/0) +op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.5bf0a800000000000000p+1:0x402df854) +res: f32(0x1.91ed3a00000000000000p+17:0x4848f69d) flags=INEXACT (18/1) +op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) +res: f32(0x1.5bc56000000000000000p+17:0x482de2b0) flags=INEXACT (18/2) +op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) +res: f32(0x1.08edee00000000000000p+18:0x488476f7) flags=INEXACT (19/0) +op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.921fb600000000000000p+1:0x40490fdb) +res: f32(0x1.ff7e0800000000000000p+31:0x4f7fbf04) flags=INEXACT (19/1) +op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) +res: f32(0x1.08ee7800000000000000p+18:0x4884773c) flags=INEXACT (19/2) +op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) +res: f32(0x1.ff800800000000000000p+31:0x4f7fc004) flags=INEXACT (20/0) +op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) +res: f32(0x1.ff840600000000000000p+31:0x4f7fc203) flags=INEXACT (20/1) +op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) +res: f32(0x1.ff820600000000000000p+31:0x4f7fc103) flags=INEXACT (20/2) +op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) +res: f32(0x1.ff860600000000000000p+31:0x4f7fc303) flags=INEXACT (21/0) +op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+15:0x477fe000) +res: f32(0x1.ff820600000000000000p+32:0x4fffc103) flags=INEXACT (21/1) +op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) +res: f32(0x1.ff800800000000000000p+32:0x4fffc004) flags=INEXACT (21/2) +op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) +res: f32(0x1.ff830600000000000000p+32:0x4fffc183) flags=INEXACT (22/0) +op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) +res: f32(0x1.ff7f8800000000000000p+33:0x507fbfc4) flags=INEXACT (22/1) +op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) +res: f32(0x1.ff840600000000000000p+32:0x4fffc203) flags=INEXACT (22/2) +op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) +res: f32(0x1.ff800800000000000000p+33:0x507fc004) flags=INEXACT (23/0) +op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) +res: f32(0x1.ff820600000000000000p+33:0x507fc103) flags=INEXACT (23/1) +op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) +res: f32(0x1.ff810600000000000000p+33:0x507fc083) flags=INEXACT (23/2) +op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) +res: f32(0x1.c0bab600000000000000p+99:0x71605d5b) flags=INEXACT (24/0) +op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) +res: f32(0x1.c0837e00000000000000p+116:0x79e041bf) flags=INEXACT (24/1) +op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) +res: f32(0x1.c0829e00000000000000p+116:0x79e0414f) flags=INEXACT (24/2) +op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/0) +op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/1) +op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/2) +op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) +res: f32(inf:0x7f800000) flags=OK (26/0) +op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) +res: f32(inf:0x7f800000) flags=OK (26/1) +op : f32(inf:0x7f800000) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) +res: f32(inf:0x7f800000) flags=OK (26/2) +op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) +res: f32(nan:0x7fc00000) flags=OK (27/0) +op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) +res: f32(nan:0x7fc00000) flags=OK (27/1) +op : f32(nan:0x7fc00000) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) +res: f32(nan:0x7fc00000) flags=OK (27/2) +op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) +res: f32(nan:0x7fe00000) flags=INVALID (28/0) +op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(inf:0x7f800000) +res: f32(nan:0x7fe00000) flags=INVALID (28/1) +op : f32(nan:0x7fa00000) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) +res: f32(nan:0x7fe00000) flags=INVALID (28/2) +op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) +res: f32(-nan:0xffe00000) flags=INVALID (29/0) +op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(nan:0x7fc00000) +res: f32(nan:0x7fe00000) flags=INVALID (29/1) +op : f32(-nan:0xffa00000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) +res: f32(nan:0x7fe00000) flags=INVALID (29/2) +op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) +res: f32(nan:0x7fe00000) flags=INVALID (30/0) +op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(nan:0x7fa00000) +res: f32(nan:0x7fe00000) flags=INVALID (30/1) +op : f32(-nan:0xffc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) +res: f32(-nan:0xffe00000) flags=INVALID (30/2) +# LP184149 +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-1:0x3f000000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(0x0.00000000000000000000p+0:0000000000) flags=OK (31/0) +op : f32(0x1.00000000000000000000p-149:0x00000001) * f32(0x1.00000000000000000000p-149:0x00000001) + f32(0x1.00000000000000000000p-149:0x00000001) +res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (32/0) diff --git a/tests/tcg/arm/Makefile.target b/tests/tcg/arm/Makefile.target index aa4e4e3782..3ddff85240 100644 --- a/tests/tcg/arm/Makefile.target +++ b/tests/tcg/arm/Makefile.target @@ -8,25 +8,33 @@ ARM_SRC=$(SRC_PATH)/tests/tcg/arm # Set search path for all sources VPATH += $(ARM_SRC) -ARM_TESTS=hello-arm test-arm-iwmmxt - -TESTS += $(ARM_TESTS) fcvt +float_madds: CFLAGS+=-mfpu=neon-vfpv4 +# Basic Hello World +ARM_TESTS = hello-arm hello-arm: CFLAGS+=-marm -ffreestanding hello-arm: LDFLAGS+=-nostdlib +# IWMXT floating point extensions +ARM_TESTS += test-arm-iwmmxt test-arm-iwmmxt: CFLAGS+=-marm -march=iwmmxt -mabi=aapcs -mfpu=fpv4-sp-d16 test-arm-iwmmxt: test-arm-iwmmxt.S $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) -ifeq ($(TARGET_NAME), arm) +# Float-convert Tests +ARM_TESTS += fcvt fcvt: LDFLAGS+=-lm # fcvt: CFLAGS+=-march=armv8.2-a+fp16 -mfpu=neon-fp-armv8 - run-fcvt: fcvt $(call run-test,fcvt,$(QEMU) $<,"$< on $(TARGET_NAME)") $(call diff-out,fcvt,$(ARM_SRC)/fcvt.ref) -endif + +# Semihosting smoke test for linux-user +ARM_TESTS += semihosting +run-semihosting: semihosting + $(call run-test,$<,$(QEMU) $< 2> $<.err, "$< on $(TARGET_NAME)") + +TESTS += $(ARM_TESTS) # On ARM Linux only supports 4k pages EXTRA_RUNS+=run-test-mmap-4096 diff --git a/tests/tcg/arm/float_convs.ref b/tests/tcg/arm/float_convs.ref new file mode 100644 index 0000000000..da8456bbc1 --- /dev/null +++ b/tests/tcg/arm/float_convs.ref @@ -0,0 +1,748 @@ +### Rounding to nearest +from single: f32(-nan:0xffa00000) + to double: f64(-nan:0x00fffc000000000000) (INVALID) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-nan:0xffc00000) + to double: f64(-nan:0x00fff8000000000000) (OK) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-inf:0xff800000) + to double: f64(-inf:0x00fff0000000000000) (OK) + to int32: -2147483648 (INVALID) + to int64: 1 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + to double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) (OK) + to int32: -2147483648 (INVALID) + to int64: 1 (INEXACT INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + to double: f64(-0x1.1874b200000000000000p+103:0x00c661874b20000000) (OK) + to int32: -2147483648 (INVALID) + to int64: 1 (INEXACT INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + to double: f64(-0x1.c0bab600000000000000p+99:0x00c62c0bab60000000) (OK) + to int32: -2147483648 (INVALID) + to int64: 1 (INEXACT INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.31f75000000000000000p-40:0xab98fba8) + to double: f64(-0x1.31f75000000000000000p-40:0x00bd731f7500000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(-0x1.50544400000000000000p-66:0x9ea82a22) + to double: f64(-0x1.50544400000000000000p-66:0x00bbd5054440000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(-0x1.00000000000000000000p-126:0x80800000) + to double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x0.00000000000000000000p+0:0000000000) + to double: f64(0x0.00000000000000000000p+0:00000000000000000000) (OK) + to int32: 0 (OK) + to int64: 0 (OK) + to uint32: 0 (OK) + to uint64: 0 (OK) +from single: f32(0x1.00000000000000000000p-126:0x00800000) + to double: f64(0x1.00000000000000000000p-126:0x003810000000000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.00000000000000000000p-25:0x33000000) + to double: f64(0x1.00000000000000000000p-25:0x003e60000000000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) + to double: f64(0x1.ffffe600000000000000p-25:0x003e6ffffe60000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) + to double: f64(0x1.ff801a00000000000000p-15:0x003f0ff801a0000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.00000c00000000000000p-14:0x38800006) + to double: f64(0x1.00000c00000000000000p-14:0x003f100000c0000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.00000000000000000000p+0:0x3f800000) + to double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) (OK) + to int32: 1 (OK) + to int64: 1 (INEXACT ) + to uint32: 1 (OK) + to uint64: 1 (INEXACT ) +from single: f32(0x1.00400000000000000000p+0:0x3f802000) + to double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) (OK) + to int32: 1 (INEXACT ) + to int64: 1 (INEXACT ) + to uint32: 1 (INEXACT ) + to uint64: 1 (INEXACT ) +from single: f32(0x1.00000000000000000000p+1:0x40000000) + to double: f64(0x1.00000000000000000000p+1:0x004000000000000000) (OK) + to int32: 2 (OK) + to int64: 2 (INEXACT ) + to uint32: 2 (OK) + to uint64: 2 (INEXACT ) +from single: f32(0x1.5bf0a800000000000000p+1:0x402df854) + to double: f64(0x1.5bf0a800000000000000p+1:0x004005bf0a80000000) (OK) + to int32: 2 (INEXACT ) + to int64: 2 (INEXACT ) + to uint32: 2 (INEXACT ) + to uint64: 2 (INEXACT ) +from single: f32(0x1.921fb600000000000000p+1:0x40490fdb) + to double: f64(0x1.921fb600000000000000p+1:0x00400921fb60000000) (OK) + to int32: 3 (INEXACT ) + to int64: 3 (INEXACT ) + to uint32: 3 (INEXACT ) + to uint64: 3 (INEXACT ) +from single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + to double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) (OK) + to int32: 65503 (OK) + to int64: 65503 (INEXACT ) + to uint32: 65503 (OK) + to uint64: 65503 (INEXACT ) +from single: f32(0x1.ffc00000000000000000p+15:0x477fe000) + to double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) (OK) + to int32: 65504 (OK) + to int64: 65504 (INEXACT ) + to uint32: 65504 (OK) + to uint64: 65504 (INEXACT ) +from single: f32(0x1.ffc20000000000000000p+15:0x477fe100) + to double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) (OK) + to int32: 65505 (OK) + to int64: 65505 (INEXACT ) + to uint32: 65505 (OK) + to uint64: 65505 (INEXACT ) +from single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + to double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) (OK) + to int32: 131007 (OK) + to int64: 131007 (INEXACT ) + to uint32: 131007 (OK) + to uint64: 131007 (INEXACT ) +from single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) + to double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) (OK) + to int32: 131008 (OK) + to int64: 131008 (INEXACT ) + to uint32: 131008 (OK) + to uint64: 131008 (INEXACT ) +from single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) + to double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) (OK) + to int32: 131009 (OK) + to int64: 131009 (INEXACT ) + to uint32: 131009 (OK) + to uint64: 131009 (INEXACT ) +from single: f32(0x1.c0bab600000000000000p+99:0x71605d5b) + to double: f64(0x1.c0bab600000000000000p+99:0x00462c0bab60000000) (OK) + to int32: 2147483647 (INVALID) + to int64: -1 (INEXACT INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INEXACT INVALID) +from single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + to double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) (OK) + to int32: 2147483647 (INVALID) + to int64: -1 (INEXACT INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INEXACT INVALID) +from single: f32(inf:0x7f800000) + to double: f64(inf:0x007ff0000000000000) (OK) + to int32: 2147483647 (INVALID) + to int64: -1 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from single: f32(nan:0x7fc00000) + to double: f64(nan:0x007ff8000000000000) (OK) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(nan:0x7fa00000) + to double: f64(nan:0x007ffc000000000000) (INVALID) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +### Rounding upwards +from single: f32(-nan:0xffa00000) + to double: f64(-nan:0x00fffc000000000000) (INVALID) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-nan:0xffc00000) + to double: f64(-nan:0x00fff8000000000000) (OK) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-inf:0xff800000) + to double: f64(-inf:0x00fff0000000000000) (OK) + to int32: -2147483648 (INVALID) + to int64: 1 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + to double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) (OK) + to int32: -2147483648 (INVALID) + to int64: 1 (INEXACT INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + to double: f64(-0x1.1874b200000000000000p+103:0x00c661874b20000000) (OK) + to int32: -2147483648 (INVALID) + to int64: 1 (INEXACT INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + to double: f64(-0x1.c0bab600000000000000p+99:0x00c62c0bab60000000) (OK) + to int32: -2147483648 (INVALID) + to int64: 1 (INEXACT INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.31f75000000000000000p-40:0xab98fba8) + to double: f64(-0x1.31f75000000000000000p-40:0x00bd731f7500000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(-0x1.50544400000000000000p-66:0x9ea82a22) + to double: f64(-0x1.50544400000000000000p-66:0x00bbd5054440000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(-0x1.00000000000000000000p-126:0x80800000) + to double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x0.00000000000000000000p+0:0000000000) + to double: f64(0x0.00000000000000000000p+0:00000000000000000000) (OK) + to int32: 0 (OK) + to int64: 0 (OK) + to uint32: 0 (OK) + to uint64: 0 (OK) +from single: f32(0x1.00000000000000000000p-126:0x00800000) + to double: f64(0x1.00000000000000000000p-126:0x003810000000000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.00000000000000000000p-25:0x33000000) + to double: f64(0x1.00000000000000000000p-25:0x003e60000000000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) + to double: f64(0x1.ffffe600000000000000p-25:0x003e6ffffe60000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) + to double: f64(0x1.ff801a00000000000000p-15:0x003f0ff801a0000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.00000c00000000000000p-14:0x38800006) + to double: f64(0x1.00000c00000000000000p-14:0x003f100000c0000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.00000000000000000000p+0:0x3f800000) + to double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) (OK) + to int32: 1 (OK) + to int64: 1 (INEXACT ) + to uint32: 1 (OK) + to uint64: 1 (INEXACT ) +from single: f32(0x1.00400000000000000000p+0:0x3f802000) + to double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) (OK) + to int32: 1 (INEXACT ) + to int64: 1 (INEXACT ) + to uint32: 1 (INEXACT ) + to uint64: 1 (INEXACT ) +from single: f32(0x1.00000000000000000000p+1:0x40000000) + to double: f64(0x1.00000000000000000000p+1:0x004000000000000000) (OK) + to int32: 2 (OK) + to int64: 2 (INEXACT ) + to uint32: 2 (OK) + to uint64: 2 (INEXACT ) +from single: f32(0x1.5bf0a800000000000000p+1:0x402df854) + to double: f64(0x1.5bf0a800000000000000p+1:0x004005bf0a80000000) (OK) + to int32: 2 (INEXACT ) + to int64: 2 (INEXACT ) + to uint32: 2 (INEXACT ) + to uint64: 2 (INEXACT ) +from single: f32(0x1.921fb600000000000000p+1:0x40490fdb) + to double: f64(0x1.921fb600000000000000p+1:0x00400921fb60000000) (OK) + to int32: 3 (INEXACT ) + to int64: 3 (INEXACT ) + to uint32: 3 (INEXACT ) + to uint64: 3 (INEXACT ) +from single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + to double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) (OK) + to int32: 65503 (OK) + to int64: 65503 (INEXACT ) + to uint32: 65503 (OK) + to uint64: 65503 (INEXACT ) +from single: f32(0x1.ffc00000000000000000p+15:0x477fe000) + to double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) (OK) + to int32: 65504 (OK) + to int64: 65504 (INEXACT ) + to uint32: 65504 (OK) + to uint64: 65504 (INEXACT ) +from single: f32(0x1.ffc20000000000000000p+15:0x477fe100) + to double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) (OK) + to int32: 65505 (OK) + to int64: 65505 (INEXACT ) + to uint32: 65505 (OK) + to uint64: 65505 (INEXACT ) +from single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + to double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) (OK) + to int32: 131007 (OK) + to int64: 131007 (INEXACT ) + to uint32: 131007 (OK) + to uint64: 131007 (INEXACT ) +from single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) + to double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) (OK) + to int32: 131008 (OK) + to int64: 131008 (INEXACT ) + to uint32: 131008 (OK) + to uint64: 131008 (INEXACT ) +from single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) + to double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) (OK) + to int32: 131009 (OK) + to int64: 131009 (INEXACT ) + to uint32: 131009 (OK) + to uint64: 131009 (INEXACT ) +from single: f32(0x1.c0bab600000000000000p+99:0x71605d5b) + to double: f64(0x1.c0bab600000000000000p+99:0x00462c0bab60000000) (OK) + to int32: 2147483647 (INVALID) + to int64: -1 (INEXACT INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INEXACT INVALID) +from single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + to double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) (OK) + to int32: 2147483647 (INVALID) + to int64: -1 (INEXACT INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INEXACT INVALID) +from single: f32(inf:0x7f800000) + to double: f64(inf:0x007ff0000000000000) (OK) + to int32: 2147483647 (INVALID) + to int64: -1 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from single: f32(nan:0x7fc00000) + to double: f64(nan:0x007ff8000000000000) (OK) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(nan:0x7fa00000) + to double: f64(nan:0x007ffc000000000000) (INVALID) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +### Rounding downwards +from single: f32(-nan:0xffa00000) + to double: f64(-nan:0x00fffc000000000000) (INVALID) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-nan:0xffc00000) + to double: f64(-nan:0x00fff8000000000000) (OK) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-inf:0xff800000) + to double: f64(-inf:0x00fff0000000000000) (OK) + to int32: -2147483648 (INVALID) + to int64: 1 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + to double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) (OK) + to int32: -2147483648 (INVALID) + to int64: 1 (INEXACT INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + to double: f64(-0x1.1874b200000000000000p+103:0x00c661874b20000000) (OK) + to int32: -2147483648 (INVALID) + to int64: 1 (INEXACT INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + to double: f64(-0x1.c0bab600000000000000p+99:0x00c62c0bab60000000) (OK) + to int32: -2147483648 (INVALID) + to int64: 1 (INEXACT INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.31f75000000000000000p-40:0xab98fba8) + to double: f64(-0x1.31f75000000000000000p-40:0x00bd731f7500000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(-0x1.50544400000000000000p-66:0x9ea82a22) + to double: f64(-0x1.50544400000000000000p-66:0x00bbd5054440000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(-0x1.00000000000000000000p-126:0x80800000) + to double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x0.00000000000000000000p+0:0000000000) + to double: f64(0x0.00000000000000000000p+0:00000000000000000000) (OK) + to int32: 0 (OK) + to int64: 0 (OK) + to uint32: 0 (OK) + to uint64: 0 (OK) +from single: f32(0x1.00000000000000000000p-126:0x00800000) + to double: f64(0x1.00000000000000000000p-126:0x003810000000000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.00000000000000000000p-25:0x33000000) + to double: f64(0x1.00000000000000000000p-25:0x003e60000000000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) + to double: f64(0x1.ffffe600000000000000p-25:0x003e6ffffe60000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) + to double: f64(0x1.ff801a00000000000000p-15:0x003f0ff801a0000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.00000c00000000000000p-14:0x38800006) + to double: f64(0x1.00000c00000000000000p-14:0x003f100000c0000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.00000000000000000000p+0:0x3f800000) + to double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) (OK) + to int32: 1 (OK) + to int64: 1 (INEXACT ) + to uint32: 1 (OK) + to uint64: 1 (INEXACT ) +from single: f32(0x1.00400000000000000000p+0:0x3f802000) + to double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) (OK) + to int32: 1 (INEXACT ) + to int64: 1 (INEXACT ) + to uint32: 1 (INEXACT ) + to uint64: 1 (INEXACT ) +from single: f32(0x1.00000000000000000000p+1:0x40000000) + to double: f64(0x1.00000000000000000000p+1:0x004000000000000000) (OK) + to int32: 2 (OK) + to int64: 2 (INEXACT ) + to uint32: 2 (OK) + to uint64: 2 (INEXACT ) +from single: f32(0x1.5bf0a800000000000000p+1:0x402df854) + to double: f64(0x1.5bf0a800000000000000p+1:0x004005bf0a80000000) (OK) + to int32: 2 (INEXACT ) + to int64: 2 (INEXACT ) + to uint32: 2 (INEXACT ) + to uint64: 2 (INEXACT ) +from single: f32(0x1.921fb600000000000000p+1:0x40490fdb) + to double: f64(0x1.921fb600000000000000p+1:0x00400921fb60000000) (OK) + to int32: 3 (INEXACT ) + to int64: 3 (INEXACT ) + to uint32: 3 (INEXACT ) + to uint64: 3 (INEXACT ) +from single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + to double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) (OK) + to int32: 65503 (OK) + to int64: 65503 (INEXACT ) + to uint32: 65503 (OK) + to uint64: 65503 (INEXACT ) +from single: f32(0x1.ffc00000000000000000p+15:0x477fe000) + to double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) (OK) + to int32: 65504 (OK) + to int64: 65504 (INEXACT ) + to uint32: 65504 (OK) + to uint64: 65504 (INEXACT ) +from single: f32(0x1.ffc20000000000000000p+15:0x477fe100) + to double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) (OK) + to int32: 65505 (OK) + to int64: 65505 (INEXACT ) + to uint32: 65505 (OK) + to uint64: 65505 (INEXACT ) +from single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + to double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) (OK) + to int32: 131007 (OK) + to int64: 131007 (INEXACT ) + to uint32: 131007 (OK) + to uint64: 131007 (INEXACT ) +from single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) + to double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) (OK) + to int32: 131008 (OK) + to int64: 131008 (INEXACT ) + to uint32: 131008 (OK) + to uint64: 131008 (INEXACT ) +from single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) + to double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) (OK) + to int32: 131009 (OK) + to int64: 131009 (INEXACT ) + to uint32: 131009 (OK) + to uint64: 131009 (INEXACT ) +from single: f32(0x1.c0bab600000000000000p+99:0x71605d5b) + to double: f64(0x1.c0bab600000000000000p+99:0x00462c0bab60000000) (OK) + to int32: 2147483647 (INVALID) + to int64: -1 (INEXACT INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INEXACT INVALID) +from single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + to double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) (OK) + to int32: 2147483647 (INVALID) + to int64: -1 (INEXACT INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INEXACT INVALID) +from single: f32(inf:0x7f800000) + to double: f64(inf:0x007ff0000000000000) (OK) + to int32: 2147483647 (INVALID) + to int64: -1 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from single: f32(nan:0x7fc00000) + to double: f64(nan:0x007ff8000000000000) (OK) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(nan:0x7fa00000) + to double: f64(nan:0x007ffc000000000000) (INVALID) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +### Rounding to zero +from single: f32(-nan:0xffa00000) + to double: f64(-nan:0x00fffc000000000000) (INVALID) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-nan:0xffc00000) + to double: f64(-nan:0x00fff8000000000000) (OK) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-inf:0xff800000) + to double: f64(-inf:0x00fff0000000000000) (OK) + to int32: -2147483648 (INVALID) + to int64: 1 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + to double: f64(-0x1.fffffe00000000000000p+127:0x00c7efffffe0000000) (OK) + to int32: -2147483648 (INVALID) + to int64: 1 (INEXACT INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + to double: f64(-0x1.1874b200000000000000p+103:0x00c661874b20000000) (OK) + to int32: -2147483648 (INVALID) + to int64: 1 (INEXACT INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + to double: f64(-0x1.c0bab600000000000000p+99:0x00c62c0bab60000000) (OK) + to int32: -2147483648 (INVALID) + to int64: 1 (INEXACT INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(-0x1.31f75000000000000000p-40:0xab98fba8) + to double: f64(-0x1.31f75000000000000000p-40:0x00bd731f7500000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(-0x1.50544400000000000000p-66:0x9ea82a22) + to double: f64(-0x1.50544400000000000000p-66:0x00bbd5054440000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(-0x1.00000000000000000000p-126:0x80800000) + to double: f64(-0x1.00000000000000000000p-126:0x00b810000000000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x0.00000000000000000000p+0:0000000000) + to double: f64(0x0.00000000000000000000p+0:00000000000000000000) (OK) + to int32: 0 (OK) + to int64: 0 (OK) + to uint32: 0 (OK) + to uint64: 0 (OK) +from single: f32(0x1.00000000000000000000p-126:0x00800000) + to double: f64(0x1.00000000000000000000p-126:0x003810000000000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.00000000000000000000p-25:0x33000000) + to double: f64(0x1.00000000000000000000p-25:0x003e60000000000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.ffffe600000000000000p-25:0x337ffff3) + to double: f64(0x1.ffffe600000000000000p-25:0x003e6ffffe60000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.ff801a00000000000000p-15:0x387fc00d) + to double: f64(0x1.ff801a00000000000000p-15:0x003f0ff801a0000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.00000c00000000000000p-14:0x38800006) + to double: f64(0x1.00000c00000000000000p-14:0x003f100000c0000000) (OK) + to int32: 0 (INEXACT ) + to int64: 0 (INEXACT ) + to uint32: 0 (INEXACT ) + to uint64: 0 (INEXACT ) +from single: f32(0x1.00000000000000000000p+0:0x3f800000) + to double: f64(0x1.00000000000000000000p+0:0x003ff0000000000000) (OK) + to int32: 1 (OK) + to int64: 1 (INEXACT ) + to uint32: 1 (OK) + to uint64: 1 (INEXACT ) +from single: f32(0x1.00400000000000000000p+0:0x3f802000) + to double: f64(0x1.00400000000000000000p+0:0x003ff0040000000000) (OK) + to int32: 1 (INEXACT ) + to int64: 1 (INEXACT ) + to uint32: 1 (INEXACT ) + to uint64: 1 (INEXACT ) +from single: f32(0x1.00000000000000000000p+1:0x40000000) + to double: f64(0x1.00000000000000000000p+1:0x004000000000000000) (OK) + to int32: 2 (OK) + to int64: 2 (INEXACT ) + to uint32: 2 (OK) + to uint64: 2 (INEXACT ) +from single: f32(0x1.5bf0a800000000000000p+1:0x402df854) + to double: f64(0x1.5bf0a800000000000000p+1:0x004005bf0a80000000) (OK) + to int32: 2 (INEXACT ) + to int64: 2 (INEXACT ) + to uint32: 2 (INEXACT ) + to uint64: 2 (INEXACT ) +from single: f32(0x1.921fb600000000000000p+1:0x40490fdb) + to double: f64(0x1.921fb600000000000000p+1:0x00400921fb60000000) (OK) + to int32: 3 (INEXACT ) + to int64: 3 (INEXACT ) + to uint32: 3 (INEXACT ) + to uint64: 3 (INEXACT ) +from single: f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + to double: f64(0x1.ffbe0000000000000000p+15:0x0040effbe000000000) (OK) + to int32: 65503 (OK) + to int64: 65503 (INEXACT ) + to uint32: 65503 (OK) + to uint64: 65503 (INEXACT ) +from single: f32(0x1.ffc00000000000000000p+15:0x477fe000) + to double: f64(0x1.ffc00000000000000000p+15:0x0040effc0000000000) (OK) + to int32: 65504 (OK) + to int64: 65504 (INEXACT ) + to uint32: 65504 (OK) + to uint64: 65504 (INEXACT ) +from single: f32(0x1.ffc20000000000000000p+15:0x477fe100) + to double: f64(0x1.ffc20000000000000000p+15:0x0040effc2000000000) (OK) + to int32: 65505 (OK) + to int64: 65505 (INEXACT ) + to uint32: 65505 (OK) + to uint64: 65505 (INEXACT ) +from single: f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + to double: f64(0x1.ffbf0000000000000000p+16:0x0040fffbf000000000) (OK) + to int32: 131007 (OK) + to int64: 131007 (INEXACT ) + to uint32: 131007 (OK) + to uint64: 131007 (INEXACT ) +from single: f32(0x1.ffc00000000000000000p+16:0x47ffe000) + to double: f64(0x1.ffc00000000000000000p+16:0x0040fffc0000000000) (OK) + to int32: 131008 (OK) + to int64: 131008 (INEXACT ) + to uint32: 131008 (OK) + to uint64: 131008 (INEXACT ) +from single: f32(0x1.ffc10000000000000000p+16:0x47ffe080) + to double: f64(0x1.ffc10000000000000000p+16:0x0040fffc1000000000) (OK) + to int32: 131009 (OK) + to int64: 131009 (INEXACT ) + to uint32: 131009 (OK) + to uint64: 131009 (INEXACT ) +from single: f32(0x1.c0bab600000000000000p+99:0x71605d5b) + to double: f64(0x1.c0bab600000000000000p+99:0x00462c0bab60000000) (OK) + to int32: 2147483647 (INVALID) + to int64: -1 (INEXACT INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INEXACT INVALID) +from single: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + to double: f64(0x1.fffffe00000000000000p+127:0x0047efffffe0000000) (OK) + to int32: 2147483647 (INVALID) + to int64: -1 (INEXACT INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INEXACT INVALID) +from single: f32(inf:0x7f800000) + to double: f64(inf:0x007ff0000000000000) (OK) + to int32: 2147483647 (INVALID) + to int64: -1 (INVALID) + to uint32: -1 (INVALID) + to uint64: -1 (INVALID) +from single: f32(nan:0x7fc00000) + to double: f64(nan:0x007ff8000000000000) (OK) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) +from single: f32(nan:0x7fa00000) + to double: f64(nan:0x007ffc000000000000) (INVALID) + to int32: 0 (INVALID) + to int64: 0 (INVALID) + to uint32: 0 (INVALID) + to uint64: 0 (INVALID) diff --git a/tests/tcg/arm/float_madds.ref b/tests/tcg/arm/float_madds.ref new file mode 100644 index 0000000000..21c0539887 --- /dev/null +++ b/tests/tcg/arm/float_madds.ref @@ -0,0 +1,768 @@ +### Rounding to nearest +op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) +res: f32(-nan:0xffe00000) flags=INVALID (0/0) +op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-nan:0xffa00000) +res: f32(-nan:0xffe00000) flags=INVALID (0/1) +op : f32(-inf:0xff800000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) +res: f32(-nan:0xffe00000) flags=INVALID (0/2) +op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) +res: f32(-nan:0xffc00000) flags=OK (1/0) +op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-nan:0xffc00000) +res: f32(-nan:0xffc00000) flags=OK (1/1) +op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) +res: f32(-nan:0xffc00000) flags=OK (1/2) +op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) +res: f32(inf:0x7f800000) flags=OK (2/0) +op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-inf:0xff800000) +res: f32(-inf:0xff800000) flags=OK (2/1) +op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) +res: f32(inf:0x7f800000) flags=OK (2/2) +op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/0) +op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/1) +op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/2) +op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (4/0) +op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) +res: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) flags=INEXACT (4/1) +op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) +res: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) flags=INEXACT (4/2) +op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) +res: f32(0x1.0c27fa00000000000000p+60:0x5d8613fd) flags=INEXACT (5/0) +op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) +res: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) flags=INEXACT (5/1) +op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) +res: f32(0x1.26c46200000000000000p+34:0x50936231) flags=INEXACT (5/2) +op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) +res: f32(0x1.91f94000000000000000p-106:0x0ac8fca0) flags=INEXACT (6/0) +op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) +res: f32(-0x1.31f75000000000000000p-40:0xab98fba8) flags=INEXACT (6/1) +op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) +res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=INEXACT (6/2) +op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (7/0) +op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) +res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=OK (7/1) +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) +res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (7/2) +op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) +res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (8/0) +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(-0x1.00000000000000000000p-126:0x80800000) +res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (8/1) +op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(-0x0.00000000000000000000p+0:0x80000000) flags=UNDERFLOW INEXACT (8/2) +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) +res: f32(0x1.00000000000000000000p-25:0x33000000) flags=OK (9/0) +op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (9/1) +op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) +res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (9/2) +op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) +res: f32(0x1.ffffe600000000000000p-25:0x337ffff3) flags=INEXACT (10/0) +op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.00000000000000000000p-126:0x00800000) +res: f32(0x1.ffffe600000000000000p-50:0x26fffff3) flags=INEXACT (10/1) +op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) +res: f32(0x1.00000000000000000000p-25:0x33000000) flags=INEXACT (10/2) +op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) +res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (11/0) +op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000000000000000000p-25:0x33000000) +res: f32(0x1.0007fe00000000000000p-25:0x330003ff) flags=INEXACT (11/1) +op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) +res: f32(0x1.0001f200000000000000p-24:0x338000f9) flags=INEXACT (11/2) +op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) +res: f32(0x1.00000c00000000000000p-14:0x38800006) flags=INEXACT (12/0) +op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) +res: f32(0x1.0ffbf400000000000000p-24:0x3387fdfa) flags=INEXACT (12/1) +op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) +res: f32(0x1.ff801c00000000000000p-15:0x387fc00e) flags=INEXACT (12/2) +op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) +res: f32(0x1.00000000000000000000p+0:0x3f800000) flags=INEXACT (13/0) +op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) +res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/1) +op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) +res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/2) +op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) +res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/0) +op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000c00000000000000p-14:0x38800006) +res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/1) +op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) +res: f32(0x1.00040200000000000000p+0:0x3f800201) flags=INEXACT (14/2) +op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) +res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/0) +op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.00000000000000000000p+0:0x3f800000) +res: f32(0x1.80400000000000000000p+1:0x40402000) flags=OK (15/1) +op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) +res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/2) +op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) +res: f32(0x1.2e185400000000000000p+2:0x40970c2a) flags=OK (16/0) +op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.00400000000000000000p+0:0x3f802000) +res: f32(0x1.9c00a800000000000000p+2:0x40ce0054) flags=OK (16/1) +op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) +res: f32(0x1.2e23d200000000000000p+2:0x409711e9) flags=INEXACT (16/2) +op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) +res: f32(0x1.12804200000000000000p+3:0x41094021) flags=INEXACT (17/0) +op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.00000000000000000000p+1:0x40000000) +res: f32(0x1.51458000000000000000p+3:0x4128a2c0) flags=INEXACT (17/1) +op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) +res: f32(0x1.200c0400000000000000p+3:0x41100602) flags=INEXACT (17/2) +op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) +res: f32(0x1.ffcf1400000000000000p+15:0x477fe78a) flags=INEXACT (18/0) +op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.5bf0a800000000000000p+1:0x402df854) +res: f32(0x1.91ed3c00000000000000p+17:0x4848f69e) flags=INEXACT (18/1) +op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) +res: f32(0x1.5bc56000000000000000p+17:0x482de2b0) flags=INEXACT (18/2) +op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) +res: f32(0x1.08edf000000000000000p+18:0x488476f8) flags=INEXACT (19/0) +op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.921fb600000000000000p+1:0x40490fdb) +res: f32(0x1.ff7e0800000000000000p+31:0x4f7fbf04) flags=INEXACT (19/1) +op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) +res: f32(0x1.08ee7a00000000000000p+18:0x4884773d) flags=INEXACT (19/2) +op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) +res: f32(0x1.ff800800000000000000p+31:0x4f7fc004) flags=INEXACT (20/0) +op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) +res: f32(0x1.ff840800000000000000p+31:0x4f7fc204) flags=INEXACT (20/1) +op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) +res: f32(0x1.ff820800000000000000p+31:0x4f7fc104) flags=INEXACT (20/2) +op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) +res: f32(0x1.ff860800000000000000p+31:0x4f7fc304) flags=INEXACT (21/0) +op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+15:0x477fe000) +res: f32(0x1.ff820800000000000000p+32:0x4fffc104) flags=INEXACT (21/1) +op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) +res: f32(0x1.ff800800000000000000p+32:0x4fffc004) flags=INEXACT (21/2) +op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) +res: f32(0x1.ff830800000000000000p+32:0x4fffc184) flags=INEXACT (22/0) +op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) +res: f32(0x1.ff7f8800000000000000p+33:0x507fbfc4) flags=INEXACT (22/1) +op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) +res: f32(0x1.ff840800000000000000p+32:0x4fffc204) flags=INEXACT (22/2) +op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) +res: f32(0x1.ff800800000000000000p+33:0x507fc004) flags=INEXACT (23/0) +op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) +res: f32(0x1.ff820800000000000000p+33:0x507fc104) flags=INEXACT (23/1) +op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) +res: f32(0x1.ff810800000000000000p+33:0x507fc084) flags=INEXACT (23/2) +op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) +res: f32(0x1.c0bab600000000000000p+99:0x71605d5b) flags=INEXACT (24/0) +op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) +res: f32(0x1.c0838000000000000000p+116:0x79e041c0) flags=INEXACT (24/1) +op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) +res: f32(0x1.c0829e00000000000000p+116:0x79e0414f) flags=INEXACT (24/2) +op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/0) +op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/1) +op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/2) +op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) +res: f32(inf:0x7f800000) flags=OK (26/0) +op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) +res: f32(inf:0x7f800000) flags=OK (26/1) +op : f32(inf:0x7f800000) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) +res: f32(inf:0x7f800000) flags=OK (26/2) +op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) +res: f32(nan:0x7fc00000) flags=OK (27/0) +op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) +res: f32(nan:0x7fc00000) flags=OK (27/1) +op : f32(nan:0x7fc00000) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) +res: f32(nan:0x7fc00000) flags=OK (27/2) +op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) +res: f32(nan:0x7fe00000) flags=INVALID (28/0) +op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(inf:0x7f800000) +res: f32(nan:0x7fe00000) flags=INVALID (28/1) +op : f32(nan:0x7fa00000) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) +res: f32(nan:0x7fe00000) flags=INVALID (28/2) +op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) +res: f32(-nan:0xffe00000) flags=INVALID (29/0) +op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(nan:0x7fc00000) +res: f32(nan:0x7fe00000) flags=INVALID (29/1) +op : f32(-nan:0xffa00000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) +res: f32(nan:0x7fe00000) flags=INVALID (29/2) +op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) +res: f32(nan:0x7fe00000) flags=INVALID (30/0) +op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(nan:0x7fa00000) +res: f32(nan:0x7fe00000) flags=INVALID (30/1) +op : f32(-nan:0xffc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) +res: f32(-nan:0xffe00000) flags=INVALID (30/2) +# LP184149 +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-1:0x3f000000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(0x0.00000000000000000000p+0:0000000000) flags=OK (31/0) +op : f32(0x1.00000000000000000000p-149:0x00000001) * f32(0x1.00000000000000000000p-149:0x00000001) + f32(0x1.00000000000000000000p-149:0x00000001) +res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (32/0) +### Rounding upwards +op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) +res: f32(-nan:0xffe00000) flags=INVALID (0/0) +op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-nan:0xffa00000) +res: f32(-nan:0xffe00000) flags=INVALID (0/1) +op : f32(-inf:0xff800000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) +res: f32(-nan:0xffe00000) flags=INVALID (0/2) +op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) +res: f32(-nan:0xffc00000) flags=OK (1/0) +op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-nan:0xffc00000) +res: f32(-nan:0xffc00000) flags=OK (1/1) +op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) +res: f32(-nan:0xffc00000) flags=OK (1/2) +op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) +res: f32(inf:0x7f800000) flags=OK (2/0) +op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-inf:0xff800000) +res: f32(-inf:0xff800000) flags=OK (2/1) +op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) +res: f32(inf:0x7f800000) flags=OK (2/2) +op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/0) +op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/1) +op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (3/2) +op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (4/0) +op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) +res: f32(-0x1.1874b000000000000000p+103:0xf30c3a58) flags=INEXACT (4/1) +op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) +res: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) flags=INEXACT (4/2) +op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) +res: f32(0x1.0c27fa00000000000000p+60:0x5d8613fd) flags=INEXACT (5/0) +op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) +res: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) flags=INEXACT (5/1) +op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) +res: f32(0x1.26c46200000000000000p+34:0x50936231) flags=INEXACT (5/2) +op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) +res: f32(0x1.91f94000000000000000p-106:0x0ac8fca0) flags=INEXACT (6/0) +op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) +res: f32(-0x1.31f74e00000000000000p-40:0xab98fba7) flags=INEXACT (6/1) +op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) +res: f32(-0x1.50544200000000000000p-66:0x9ea82a21) flags=INEXACT (6/2) +op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (7/0) +op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) +res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=OK (7/1) +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) +res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (7/2) +op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) +res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (8/0) +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(-0x1.00000000000000000000p-126:0x80800000) +res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (8/1) +op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(-0x0.00000000000000000000p+0:0x80000000) flags=UNDERFLOW INEXACT (8/2) +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) +res: f32(0x1.00000000000000000000p-25:0x33000000) flags=OK (9/0) +op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (9/1) +op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) +res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (9/2) +op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) +res: f32(0x1.ffffe800000000000000p-25:0x337ffff4) flags=INEXACT (10/0) +op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.00000000000000000000p-126:0x00800000) +res: f32(0x1.ffffe800000000000000p-50:0x26fffff4) flags=INEXACT (10/1) +op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) +res: f32(0x1.00000200000000000000p-25:0x33000001) flags=INEXACT (10/2) +op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) +res: f32(0x1.ff801c00000000000000p-15:0x387fc00e) flags=INEXACT (11/0) +op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000000000000000000p-25:0x33000000) +res: f32(0x1.00080000000000000000p-25:0x33000400) flags=INEXACT (11/1) +op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) +res: f32(0x1.0001f400000000000000p-24:0x338000fa) flags=INEXACT (11/2) +op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) +res: f32(0x1.00000e00000000000000p-14:0x38800007) flags=INEXACT (12/0) +op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) +res: f32(0x1.0ffbf600000000000000p-24:0x3387fdfb) flags=INEXACT (12/1) +op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) +res: f32(0x1.ff801c00000000000000p-15:0x387fc00e) flags=INEXACT (12/2) +op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) +res: f32(0x1.00000200000000000000p+0:0x3f800001) flags=INEXACT (13/0) +op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) +res: f32(0x1.ffc01a00000000000000p-14:0x38ffe00d) flags=INEXACT (13/1) +op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) +res: f32(0x1.ffc01a00000000000000p-14:0x38ffe00d) flags=INEXACT (13/2) +op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) +res: f32(0x1.00440200000000000000p+0:0x3f802201) flags=INEXACT (14/0) +op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000c00000000000000p-14:0x38800006) +res: f32(0x1.00440200000000000000p+0:0x3f802201) flags=INEXACT (14/1) +op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) +res: f32(0x1.00040200000000000000p+0:0x3f800201) flags=INEXACT (14/2) +op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) +res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/0) +op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.00000000000000000000p+0:0x3f800000) +res: f32(0x1.80400000000000000000p+1:0x40402000) flags=OK (15/1) +op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) +res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/2) +op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) +res: f32(0x1.2e185400000000000000p+2:0x40970c2a) flags=OK (16/0) +op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.00400000000000000000p+0:0x3f802000) +res: f32(0x1.9c00a800000000000000p+2:0x40ce0054) flags=OK (16/1) +op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) +res: f32(0x1.2e23d400000000000000p+2:0x409711ea) flags=INEXACT (16/2) +op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) +res: f32(0x1.12804200000000000000p+3:0x41094021) flags=INEXACT (17/0) +op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.00000000000000000000p+1:0x40000000) +res: f32(0x1.51458200000000000000p+3:0x4128a2c1) flags=INEXACT (17/1) +op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) +res: f32(0x1.200c0600000000000000p+3:0x41100603) flags=INEXACT (17/2) +op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) +res: f32(0x1.ffcf1600000000000000p+15:0x477fe78b) flags=INEXACT (18/0) +op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.5bf0a800000000000000p+1:0x402df854) +res: f32(0x1.91ed3c00000000000000p+17:0x4848f69e) flags=INEXACT (18/1) +op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) +res: f32(0x1.5bc56200000000000000p+17:0x482de2b1) flags=INEXACT (18/2) +op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) +res: f32(0x1.08edf000000000000000p+18:0x488476f8) flags=INEXACT (19/0) +op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.921fb600000000000000p+1:0x40490fdb) +res: f32(0x1.ff7e0a00000000000000p+31:0x4f7fbf05) flags=INEXACT (19/1) +op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) +res: f32(0x1.08ee7a00000000000000p+18:0x4884773d) flags=INEXACT (19/2) +op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) +res: f32(0x1.ff800a00000000000000p+31:0x4f7fc005) flags=INEXACT (20/0) +op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) +res: f32(0x1.ff840800000000000000p+31:0x4f7fc204) flags=INEXACT (20/1) +op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) +res: f32(0x1.ff820800000000000000p+31:0x4f7fc104) flags=INEXACT (20/2) +op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) +res: f32(0x1.ff860800000000000000p+31:0x4f7fc304) flags=INEXACT (21/0) +op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+15:0x477fe000) +res: f32(0x1.ff820800000000000000p+32:0x4fffc104) flags=INEXACT (21/1) +op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) +res: f32(0x1.ff800a00000000000000p+32:0x4fffc005) flags=INEXACT (21/2) +op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) +res: f32(0x1.ff830800000000000000p+32:0x4fffc184) flags=INEXACT (22/0) +op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) +res: f32(0x1.ff7f8a00000000000000p+33:0x507fbfc5) flags=INEXACT (22/1) +op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) +res: f32(0x1.ff840800000000000000p+32:0x4fffc204) flags=INEXACT (22/2) +op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) +res: f32(0x1.ff800a00000000000000p+33:0x507fc005) flags=INEXACT (23/0) +op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) +res: f32(0x1.ff820800000000000000p+33:0x507fc104) flags=INEXACT (23/1) +op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) +res: f32(0x1.ff810800000000000000p+33:0x507fc084) flags=INEXACT (23/2) +op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) +res: f32(0x1.c0bab800000000000000p+99:0x71605d5c) flags=INEXACT (24/0) +op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) +res: f32(0x1.c0838000000000000000p+116:0x79e041c0) flags=INEXACT (24/1) +op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) +res: f32(0x1.c082a000000000000000p+116:0x79e04150) flags=INEXACT (24/2) +op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/0) +op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/1) +op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) +res: f32(inf:0x7f800000) flags=OVERFLOW INEXACT (25/2) +op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) +res: f32(inf:0x7f800000) flags=OK (26/0) +op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) +res: f32(inf:0x7f800000) flags=OK (26/1) +op : f32(inf:0x7f800000) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) +res: f32(inf:0x7f800000) flags=OK (26/2) +op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) +res: f32(nan:0x7fc00000) flags=OK (27/0) +op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) +res: f32(nan:0x7fc00000) flags=OK (27/1) +op : f32(nan:0x7fc00000) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) +res: f32(nan:0x7fc00000) flags=OK (27/2) +op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) +res: f32(nan:0x7fe00000) flags=INVALID (28/0) +op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(inf:0x7f800000) +res: f32(nan:0x7fe00000) flags=INVALID (28/1) +op : f32(nan:0x7fa00000) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) +res: f32(nan:0x7fe00000) flags=INVALID (28/2) +op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) +res: f32(-nan:0xffe00000) flags=INVALID (29/0) +op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(nan:0x7fc00000) +res: f32(nan:0x7fe00000) flags=INVALID (29/1) +op : f32(-nan:0xffa00000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) +res: f32(nan:0x7fe00000) flags=INVALID (29/2) +op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) +res: f32(nan:0x7fe00000) flags=INVALID (30/0) +op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(nan:0x7fa00000) +res: f32(nan:0x7fe00000) flags=INVALID (30/1) +op : f32(-nan:0xffc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) +res: f32(-nan:0xffe00000) flags=INVALID (30/2) +# LP184149 +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-1:0x3f000000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(0x0.00000000000000000000p+0:0000000000) flags=OK (31/0) +op : f32(0x1.00000000000000000000p-149:0x00000001) * f32(0x1.00000000000000000000p-149:0x00000001) + f32(0x1.00000000000000000000p-149:0x00000001) +res: f32(0x1.00000000000000000000p-148:0x00000002) flags=UNDERFLOW INEXACT (32/0) +### Rounding downwards +op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) +res: f32(-nan:0xffe00000) flags=INVALID (0/0) +op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-nan:0xffa00000) +res: f32(-nan:0xffe00000) flags=INVALID (0/1) +op : f32(-inf:0xff800000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) +res: f32(-nan:0xffe00000) flags=INVALID (0/2) +op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) +res: f32(-nan:0xffc00000) flags=OK (1/0) +op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-nan:0xffc00000) +res: f32(-nan:0xffc00000) flags=OK (1/1) +op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) +res: f32(-nan:0xffc00000) flags=OK (1/2) +op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) +res: f32(inf:0x7f800000) flags=OK (2/0) +op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-inf:0xff800000) +res: f32(-inf:0xff800000) flags=OK (2/1) +op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) +res: f32(inf:0x7f800000) flags=OK (2/2) +op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/0) +op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/1) +op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/2) +op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (4/0) +op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) +res: f32(-0x1.1874b200000000000000p+103:0xf30c3a59) flags=INEXACT (4/1) +op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) +res: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) flags=INEXACT (4/2) +op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) +res: f32(0x1.0c27f800000000000000p+60:0x5d8613fc) flags=INEXACT (5/0) +op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) +res: f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) flags=INEXACT (5/1) +op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) +res: f32(0x1.26c46000000000000000p+34:0x50936230) flags=INEXACT (5/2) +op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) +res: f32(0x1.91f93e00000000000000p-106:0x0ac8fc9f) flags=INEXACT (6/0) +op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) +res: f32(-0x1.31f75000000000000000p-40:0xab98fba8) flags=INEXACT (6/1) +op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) +res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=INEXACT (6/2) +op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (7/0) +op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) +res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=OK (7/1) +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) +res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (7/2) +op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) +res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (8/0) +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(-0x1.00000000000000000000p-126:0x80800000) +res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (8/1) +op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(-0x1.00000000000000000000p-149:0x80000001) flags=UNDERFLOW INEXACT (8/2) +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) +res: f32(0x1.00000000000000000000p-25:0x33000000) flags=OK (9/0) +op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (9/1) +op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) +res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (9/2) +op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) +res: f32(0x1.ffffe600000000000000p-25:0x337ffff3) flags=INEXACT (10/0) +op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.00000000000000000000p-126:0x00800000) +res: f32(0x1.ffffe600000000000000p-50:0x26fffff3) flags=INEXACT (10/1) +op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) +res: f32(0x1.00000000000000000000p-25:0x33000000) flags=INEXACT (10/2) +op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) +res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (11/0) +op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000000000000000000p-25:0x33000000) +res: f32(0x1.0007fe00000000000000p-25:0x330003ff) flags=INEXACT (11/1) +op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) +res: f32(0x1.0001f200000000000000p-24:0x338000f9) flags=INEXACT (11/2) +op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) +res: f32(0x1.00000c00000000000000p-14:0x38800006) flags=INEXACT (12/0) +op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) +res: f32(0x1.0ffbf400000000000000p-24:0x3387fdfa) flags=INEXACT (12/1) +op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) +res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (12/2) +op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) +res: f32(0x1.00000000000000000000p+0:0x3f800000) flags=INEXACT (13/0) +op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) +res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/1) +op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) +res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/2) +op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) +res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/0) +op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000c00000000000000p-14:0x38800006) +res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/1) +op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) +res: f32(0x1.00040000000000000000p+0:0x3f800200) flags=INEXACT (14/2) +op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) +res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/0) +op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.00000000000000000000p+0:0x3f800000) +res: f32(0x1.80400000000000000000p+1:0x40402000) flags=OK (15/1) +op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) +res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/2) +op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) +res: f32(0x1.2e185400000000000000p+2:0x40970c2a) flags=OK (16/0) +op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.00400000000000000000p+0:0x3f802000) +res: f32(0x1.9c00a800000000000000p+2:0x40ce0054) flags=OK (16/1) +op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) +res: f32(0x1.2e23d200000000000000p+2:0x409711e9) flags=INEXACT (16/2) +op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) +res: f32(0x1.12804000000000000000p+3:0x41094020) flags=INEXACT (17/0) +op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.00000000000000000000p+1:0x40000000) +res: f32(0x1.51458000000000000000p+3:0x4128a2c0) flags=INEXACT (17/1) +op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) +res: f32(0x1.200c0400000000000000p+3:0x41100602) flags=INEXACT (17/2) +op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) +res: f32(0x1.ffcf1400000000000000p+15:0x477fe78a) flags=INEXACT (18/0) +op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.5bf0a800000000000000p+1:0x402df854) +res: f32(0x1.91ed3a00000000000000p+17:0x4848f69d) flags=INEXACT (18/1) +op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) +res: f32(0x1.5bc56000000000000000p+17:0x482de2b0) flags=INEXACT (18/2) +op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) +res: f32(0x1.08edee00000000000000p+18:0x488476f7) flags=INEXACT (19/0) +op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.921fb600000000000000p+1:0x40490fdb) +res: f32(0x1.ff7e0800000000000000p+31:0x4f7fbf04) flags=INEXACT (19/1) +op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) +res: f32(0x1.08ee7800000000000000p+18:0x4884773c) flags=INEXACT (19/2) +op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) +res: f32(0x1.ff800800000000000000p+31:0x4f7fc004) flags=INEXACT (20/0) +op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) +res: f32(0x1.ff840600000000000000p+31:0x4f7fc203) flags=INEXACT (20/1) +op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) +res: f32(0x1.ff820600000000000000p+31:0x4f7fc103) flags=INEXACT (20/2) +op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) +res: f32(0x1.ff860600000000000000p+31:0x4f7fc303) flags=INEXACT (21/0) +op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+15:0x477fe000) +res: f32(0x1.ff820600000000000000p+32:0x4fffc103) flags=INEXACT (21/1) +op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) +res: f32(0x1.ff800800000000000000p+32:0x4fffc004) flags=INEXACT (21/2) +op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) +res: f32(0x1.ff830600000000000000p+32:0x4fffc183) flags=INEXACT (22/0) +op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) +res: f32(0x1.ff7f8800000000000000p+33:0x507fbfc4) flags=INEXACT (22/1) +op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) +res: f32(0x1.ff840600000000000000p+32:0x4fffc203) flags=INEXACT (22/2) +op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) +res: f32(0x1.ff800800000000000000p+33:0x507fc004) flags=INEXACT (23/0) +op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) +res: f32(0x1.ff820600000000000000p+33:0x507fc103) flags=INEXACT (23/1) +op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) +res: f32(0x1.ff810600000000000000p+33:0x507fc083) flags=INEXACT (23/2) +op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) +res: f32(0x1.c0bab600000000000000p+99:0x71605d5b) flags=INEXACT (24/0) +op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) +res: f32(0x1.c0837e00000000000000p+116:0x79e041bf) flags=INEXACT (24/1) +op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) +res: f32(0x1.c0829e00000000000000p+116:0x79e0414f) flags=INEXACT (24/2) +op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/0) +op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/1) +op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/2) +op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) +res: f32(inf:0x7f800000) flags=OK (26/0) +op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) +res: f32(inf:0x7f800000) flags=OK (26/1) +op : f32(inf:0x7f800000) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) +res: f32(inf:0x7f800000) flags=OK (26/2) +op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) +res: f32(nan:0x7fc00000) flags=OK (27/0) +op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) +res: f32(nan:0x7fc00000) flags=OK (27/1) +op : f32(nan:0x7fc00000) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) +res: f32(nan:0x7fc00000) flags=OK (27/2) +op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) +res: f32(nan:0x7fe00000) flags=INVALID (28/0) +op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(inf:0x7f800000) +res: f32(nan:0x7fe00000) flags=INVALID (28/1) +op : f32(nan:0x7fa00000) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) +res: f32(nan:0x7fe00000) flags=INVALID (28/2) +op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) +res: f32(-nan:0xffe00000) flags=INVALID (29/0) +op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(nan:0x7fc00000) +res: f32(nan:0x7fe00000) flags=INVALID (29/1) +op : f32(-nan:0xffa00000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) +res: f32(nan:0x7fe00000) flags=INVALID (29/2) +op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) +res: f32(nan:0x7fe00000) flags=INVALID (30/0) +op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(nan:0x7fa00000) +res: f32(nan:0x7fe00000) flags=INVALID (30/1) +op : f32(-nan:0xffc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) +res: f32(-nan:0xffe00000) flags=INVALID (30/2) +# LP184149 +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-1:0x3f000000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(0x0.00000000000000000000p+0:0000000000) flags=OK (31/0) +op : f32(0x1.00000000000000000000p-149:0x00000001) * f32(0x1.00000000000000000000p-149:0x00000001) + f32(0x1.00000000000000000000p-149:0x00000001) +res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (32/0) +### Rounding to zero +op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) +res: f32(-nan:0xffe00000) flags=INVALID (0/0) +op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-nan:0xffa00000) +res: f32(-nan:0xffe00000) flags=INVALID (0/1) +op : f32(-inf:0xff800000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) +res: f32(-nan:0xffe00000) flags=INVALID (0/2) +op : f32(-nan:0xffc00000) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) +res: f32(-nan:0xffc00000) flags=OK (1/0) +op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-nan:0xffc00000) +res: f32(-nan:0xffc00000) flags=OK (1/1) +op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-nan:0xffc00000) + f32(-inf:0xff800000) +res: f32(-nan:0xffc00000) flags=OK (1/2) +op : f32(-inf:0xff800000) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) +res: f32(inf:0x7f800000) flags=OK (2/0) +op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-inf:0xff800000) +res: f32(-inf:0xff800000) flags=OK (2/1) +op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-inf:0xff800000) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) +res: f32(inf:0x7f800000) flags=OK (2/2) +op : f32(-0x1.fffffe00000000000000p+127:0xff7fffff) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/0) +op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.fffffe00000000000000p+127:0xff7fffff) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/1) +op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.fffffe00000000000000p+127:0xff7fffff) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (3/2) +op : f32(-0x1.1874b200000000000000p+103:0xf30c3a59) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (4/0) +op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.1874b200000000000000p+103:0xf30c3a59) +res: f32(-0x1.1874b000000000000000p+103:0xf30c3a58) flags=INEXACT (4/1) +op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.1874b200000000000000p+103:0xf30c3a59) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) +res: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) flags=INEXACT (4/2) +op : f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) +res: f32(0x1.0c27f800000000000000p+60:0x5d8613fc) flags=INEXACT (5/0) +op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) +res: f32(-0x1.c0bab400000000000000p+99:0xf1605d5a) flags=INEXACT (5/1) +op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.c0bab600000000000000p+99:0xf1605d5b) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) +res: f32(0x1.26c46000000000000000p+34:0x50936230) flags=INEXACT (5/2) +op : f32(-0x1.31f75000000000000000p-40:0xab98fba8) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) +res: f32(0x1.91f93e00000000000000p-106:0x0ac8fc9f) flags=INEXACT (6/0) +op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(-0x1.31f75000000000000000p-40:0xab98fba8) +res: f32(-0x1.31f74e00000000000000p-40:0xab98fba7) flags=INEXACT (6/1) +op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(-0x1.31f75000000000000000p-40:0xab98fba8) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) +res: f32(-0x1.50544200000000000000p-66:0x9ea82a21) flags=INEXACT (6/2) +op : f32(-0x1.50544400000000000000p-66:0x9ea82a22) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (7/0) +op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(-0x1.50544400000000000000p-66:0x9ea82a22) +res: f32(-0x1.50544400000000000000p-66:0x9ea82a22) flags=OK (7/1) +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(-0x1.50544400000000000000p-66:0x9ea82a22) + f32(-0x1.00000000000000000000p-126:0x80800000) +res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (7/2) +op : f32(-0x1.00000000000000000000p-126:0x80800000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) +res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (8/0) +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(-0x1.00000000000000000000p-126:0x80800000) +res: f32(-0x1.00000000000000000000p-126:0x80800000) flags=OK (8/1) +op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(-0x1.00000000000000000000p-126:0x80800000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(-0x0.00000000000000000000p+0:0x80000000) flags=UNDERFLOW INEXACT (8/2) +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) +res: f32(0x1.00000000000000000000p-25:0x33000000) flags=OK (9/0) +op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(0x0.00000000000000000000p+0:0000000000) flags=UNDERFLOW INEXACT (9/1) +op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x0.00000000000000000000p+0:0000000000) + f32(0x1.00000000000000000000p-126:0x00800000) +res: f32(0x1.00000000000000000000p-126:0x00800000) flags=OK (9/2) +op : f32(0x1.00000000000000000000p-126:0x00800000) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) +res: f32(0x1.ffffe600000000000000p-25:0x337ffff3) flags=INEXACT (10/0) +op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.00000000000000000000p-126:0x00800000) +res: f32(0x1.ffffe600000000000000p-50:0x26fffff3) flags=INEXACT (10/1) +op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.00000000000000000000p-126:0x00800000) + f32(0x1.00000000000000000000p-25:0x33000000) +res: f32(0x1.00000000000000000000p-25:0x33000000) flags=INEXACT (10/2) +op : f32(0x1.00000000000000000000p-25:0x33000000) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) +res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (11/0) +op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000000000000000000p-25:0x33000000) +res: f32(0x1.0007fe00000000000000p-25:0x330003ff) flags=INEXACT (11/1) +op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000000000000000000p-25:0x33000000) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) +res: f32(0x1.0001f200000000000000p-24:0x338000f9) flags=INEXACT (11/2) +op : f32(0x1.ffffe600000000000000p-25:0x337ffff3) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) +res: f32(0x1.00000c00000000000000p-14:0x38800006) flags=INEXACT (12/0) +op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.ffffe600000000000000p-25:0x337ffff3) +res: f32(0x1.0ffbf400000000000000p-24:0x3387fdfa) flags=INEXACT (12/1) +op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.ffffe600000000000000p-25:0x337ffff3) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) +res: f32(0x1.ff801a00000000000000p-15:0x387fc00d) flags=INEXACT (12/2) +op : f32(0x1.ff801a00000000000000p-15:0x387fc00d) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) +res: f32(0x1.00000000000000000000p+0:0x3f800000) flags=INEXACT (13/0) +op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.ff801a00000000000000p-15:0x387fc00d) +res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/1) +op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.ff801a00000000000000p-15:0x387fc00d) + f32(0x1.00000c00000000000000p-14:0x38800006) +res: f32(0x1.ffc01800000000000000p-14:0x38ffe00c) flags=INEXACT (13/2) +op : f32(0x1.00000c00000000000000p-14:0x38800006) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) +res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/0) +op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000c00000000000000p-14:0x38800006) +res: f32(0x1.00440000000000000000p+0:0x3f802200) flags=INEXACT (14/1) +op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000c00000000000000p-14:0x38800006) + f32(0x1.00000000000000000000p+0:0x3f800000) +res: f32(0x1.00040000000000000000p+0:0x3f800200) flags=INEXACT (14/2) +op : f32(0x1.00000000000000000000p+0:0x3f800000) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) +res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/0) +op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.00000000000000000000p+0:0x3f800000) +res: f32(0x1.80400000000000000000p+1:0x40402000) flags=OK (15/1) +op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.00000000000000000000p+0:0x3f800000) + f32(0x1.00400000000000000000p+0:0x3f802000) +res: f32(0x1.80200000000000000000p+1:0x40401000) flags=OK (15/2) +op : f32(0x1.00400000000000000000p+0:0x3f802000) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) +res: f32(0x1.2e185400000000000000p+2:0x40970c2a) flags=OK (16/0) +op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.00400000000000000000p+0:0x3f802000) +res: f32(0x1.9c00a800000000000000p+2:0x40ce0054) flags=OK (16/1) +op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.00400000000000000000p+0:0x3f802000) + f32(0x1.00000000000000000000p+1:0x40000000) +res: f32(0x1.2e23d200000000000000p+2:0x409711e9) flags=INEXACT (16/2) +op : f32(0x1.00000000000000000000p+1:0x40000000) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) +res: f32(0x1.12804000000000000000p+3:0x41094020) flags=INEXACT (17/0) +op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.00000000000000000000p+1:0x40000000) +res: f32(0x1.51458000000000000000p+3:0x4128a2c0) flags=INEXACT (17/1) +op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.00000000000000000000p+1:0x40000000) + f32(0x1.5bf0a800000000000000p+1:0x402df854) +res: f32(0x1.200c0400000000000000p+3:0x41100602) flags=INEXACT (17/2) +op : f32(0x1.5bf0a800000000000000p+1:0x402df854) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) +res: f32(0x1.ffcf1400000000000000p+15:0x477fe78a) flags=INEXACT (18/0) +op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.5bf0a800000000000000p+1:0x402df854) +res: f32(0x1.91ed3a00000000000000p+17:0x4848f69d) flags=INEXACT (18/1) +op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.5bf0a800000000000000p+1:0x402df854) + f32(0x1.921fb600000000000000p+1:0x40490fdb) +res: f32(0x1.5bc56000000000000000p+17:0x482de2b0) flags=INEXACT (18/2) +op : f32(0x1.921fb600000000000000p+1:0x40490fdb) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) +res: f32(0x1.08edee00000000000000p+18:0x488476f7) flags=INEXACT (19/0) +op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.921fb600000000000000p+1:0x40490fdb) +res: f32(0x1.ff7e0800000000000000p+31:0x4f7fbf04) flags=INEXACT (19/1) +op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.921fb600000000000000p+1:0x40490fdb) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) +res: f32(0x1.08ee7800000000000000p+18:0x4884773c) flags=INEXACT (19/2) +op : f32(0x1.ffbe0000000000000000p+15:0x477fdf00) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) +res: f32(0x1.ff800800000000000000p+31:0x4f7fc004) flags=INEXACT (20/0) +op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbe0000000000000000p+15:0x477fdf00) +res: f32(0x1.ff840600000000000000p+31:0x4f7fc203) flags=INEXACT (20/1) +op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbe0000000000000000p+15:0x477fdf00) + f32(0x1.ffc00000000000000000p+15:0x477fe000) +res: f32(0x1.ff820600000000000000p+31:0x4f7fc103) flags=INEXACT (20/2) +op : f32(0x1.ffc00000000000000000p+15:0x477fe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) +res: f32(0x1.ff860600000000000000p+31:0x4f7fc303) flags=INEXACT (21/0) +op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+15:0x477fe000) +res: f32(0x1.ff820600000000000000p+32:0x4fffc103) flags=INEXACT (21/1) +op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+15:0x477fe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) +res: f32(0x1.ff800800000000000000p+32:0x4fffc004) flags=INEXACT (21/2) +op : f32(0x1.ffc20000000000000000p+15:0x477fe100) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) +res: f32(0x1.ff830600000000000000p+32:0x4fffc183) flags=INEXACT (22/0) +op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc20000000000000000p+15:0x477fe100) +res: f32(0x1.ff7f8800000000000000p+33:0x507fbfc4) flags=INEXACT (22/1) +op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc20000000000000000p+15:0x477fe100) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) +res: f32(0x1.ff840600000000000000p+32:0x4fffc203) flags=INEXACT (22/2) +op : f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) +res: f32(0x1.ff800800000000000000p+33:0x507fc004) flags=INEXACT (23/0) +op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) +res: f32(0x1.ff820600000000000000p+33:0x507fc103) flags=INEXACT (23/1) +op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.ffbf0000000000000000p+16:0x47ffdf80) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) +res: f32(0x1.ff810600000000000000p+33:0x507fc083) flags=INEXACT (23/2) +op : f32(0x1.ffc00000000000000000p+16:0x47ffe000) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) +res: f32(0x1.c0bab600000000000000p+99:0x71605d5b) flags=INEXACT (24/0) +op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.ffc00000000000000000p+16:0x47ffe000) +res: f32(0x1.c0837e00000000000000p+116:0x79e041bf) flags=INEXACT (24/1) +op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.ffc00000000000000000p+16:0x47ffe000) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) +res: f32(0x1.c0829e00000000000000p+116:0x79e0414f) flags=INEXACT (24/2) +op : f32(0x1.ffc10000000000000000p+16:0x47ffe080) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/0) +op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(0x1.ffc10000000000000000p+16:0x47ffe080) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/1) +op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(0x1.ffc10000000000000000p+16:0x47ffe080) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) +res: f32(0x1.fffffe00000000000000p+127:0x7f7fffff) flags=OVERFLOW INEXACT (25/2) +op : f32(0x1.c0bab600000000000000p+99:0x71605d5b) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) +res: f32(inf:0x7f800000) flags=OK (26/0) +op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(0x1.c0bab600000000000000p+99:0x71605d5b) +res: f32(inf:0x7f800000) flags=OK (26/1) +op : f32(inf:0x7f800000) * f32(0x1.c0bab600000000000000p+99:0x71605d5b) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) +res: f32(inf:0x7f800000) flags=OK (26/2) +op : f32(0x1.fffffe00000000000000p+127:0x7f7fffff) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) +res: f32(nan:0x7fc00000) flags=OK (27/0) +op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(0x1.fffffe00000000000000p+127:0x7f7fffff) +res: f32(nan:0x7fc00000) flags=OK (27/1) +op : f32(nan:0x7fc00000) * f32(0x1.fffffe00000000000000p+127:0x7f7fffff) + f32(inf:0x7f800000) +res: f32(nan:0x7fc00000) flags=OK (27/2) +op : f32(inf:0x7f800000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) +res: f32(nan:0x7fe00000) flags=INVALID (28/0) +op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(inf:0x7f800000) +res: f32(nan:0x7fe00000) flags=INVALID (28/1) +op : f32(nan:0x7fa00000) * f32(inf:0x7f800000) + f32(nan:0x7fc00000) +res: f32(nan:0x7fe00000) flags=INVALID (28/2) +op : f32(nan:0x7fc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) +res: f32(-nan:0xffe00000) flags=INVALID (29/0) +op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(nan:0x7fc00000) +res: f32(nan:0x7fe00000) flags=INVALID (29/1) +op : f32(-nan:0xffa00000) * f32(nan:0x7fc00000) + f32(nan:0x7fa00000) +res: f32(nan:0x7fe00000) flags=INVALID (29/2) +op : f32(nan:0x7fa00000) * f32(-nan:0xffa00000) + f32(-nan:0xffc00000) +res: f32(nan:0x7fe00000) flags=INVALID (30/0) +op : f32(-nan:0xffa00000) * f32(-nan:0xffc00000) + f32(nan:0x7fa00000) +res: f32(nan:0x7fe00000) flags=INVALID (30/1) +op : f32(-nan:0xffc00000) * f32(nan:0x7fa00000) + f32(-nan:0xffa00000) +res: f32(-nan:0xffe00000) flags=INVALID (30/2) +# LP184149 +op : f32(0x0.00000000000000000000p+0:0000000000) * f32(0x1.00000000000000000000p-1:0x3f000000) + f32(0x0.00000000000000000000p+0:0000000000) +res: f32(0x0.00000000000000000000p+0:0000000000) flags=OK (31/0) +op : f32(0x1.00000000000000000000p-149:0x00000001) * f32(0x1.00000000000000000000p-149:0x00000001) + f32(0x1.00000000000000000000p-149:0x00000001) +res: f32(0x1.00000000000000000000p-149:0x00000001) flags=UNDERFLOW INEXACT (32/0) diff --git a/tests/tcg/arm/semihosting.c b/tests/tcg/arm/semihosting.c new file mode 100644 index 0000000000..09c89cb481 --- /dev/null +++ b/tests/tcg/arm/semihosting.c @@ -0,0 +1,45 @@ +/* + * linux-user semihosting checks + * + * Copyright (c) 2019 + * Written by Alex BennĂ©e <alex.bennee@linaro.org> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include <stdint.h> + +#define SYS_WRITE0 0x04 +#define SYS_REPORTEXC 0x18 + +void __semi_call(uintptr_t type, uintptr_t arg0) +{ +#if defined(__arm__) + register uintptr_t t asm("r0") = type; + register uintptr_t a0 asm("r1") = arg0; + asm("svc 0xab" + : /* no return */ + : "r" (t), "r" (a0)); +#else + register uintptr_t t asm("x0") = type; + register uintptr_t a0 asm("x1") = arg0; + asm("hlt 0xf000" + : /* no return */ + : "r" (t), "r" (a0)); +#endif +} + +int main(int argc, char *argv[argc]) +{ +#if defined(__arm__) + uintptr_t exit_code = 0x20026; +#else + uintptr_t exit_block[2] = {0x20026, 0}; + uintptr_t exit_code = (uintptr_t) &exit_block; +#endif + + __semi_call(SYS_WRITE0, (uintptr_t) "Hello World"); + __semi_call(SYS_REPORTEXC, exit_code); + /* if we get here we failed */ + return -1; +} diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target index 6b1e30e2fe..035b09c853 100644 --- a/tests/tcg/multiarch/Makefile.target +++ b/tests/tcg/multiarch/Makefile.target @@ -10,20 +10,22 @@ MULTIARCH_SRC=$(SRC_PATH)/tests/tcg/multiarch # Set search path for all sources VPATH += $(MULTIARCH_SRC) MULTIARCH_SRCS =$(notdir $(wildcard $(MULTIARCH_SRC)/*.c)) -MULTIARCH_TESTS =$(MULTIARCH_SRCS:.c=) - -# FIXME: ppc64abi32 linux-test seems to have issues but the other basic tests work -ifeq ($(TARGET_NAME),ppc64abi32) -BROKEN_TESTS = linux-test -endif - -# Update TESTS -TESTS += $(filter-out $(BROKEN_TESTS), $(MULTIARCH_TESTS)) +MULTIARCH_TESTS =$(filter-out float_helpers, $(MULTIARCH_SRCS:.c=)) # # The following are any additional rules needed to build things # + +float_%: LDFLAGS+=-lm +float_%: float_%.c float_helpers.c + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< $(MULTIARCH_SRC)/float_helpers.c -o $@ $(LDFLAGS) + +run-float_%: float_% + $(call run-test,$<, $(QEMU) $(QEMU_OPTS) $<,"$< on $(TARGET_NAME)") + $(call conditional-diff-out,$<,$(SRC_PATH)/tests/tcg/$(TARGET_NAME)/$<.ref) + + testthread: LDFLAGS+=-lpthread # We define the runner for test-mmap after the individual @@ -39,3 +41,6 @@ run-test-mmap: test-mmap run-test-mmap-%: test-mmap $(call run-test, test-mmap-$*, $(QEMU) -p $* $<,\ "$< ($* byte pages) on $(TARGET_NAME)") + +# Update TESTS +TESTS += $(MULTIARCH_TESTS) diff --git a/tests/tcg/multiarch/float_convs.c b/tests/tcg/multiarch/float_convs.c new file mode 100644 index 0000000000..47e24b8b16 --- /dev/null +++ b/tests/tcg/multiarch/float_convs.c @@ -0,0 +1,105 @@ +/* + * Floating Point Convert Single to Various + * + * Copyright (c) 2019 Linaro + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <float.h> +#include <fenv.h> + + +#include "float_helpers.h" + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +typedef struct { + int flag; + char *desc; +} float_mapping; + +float_mapping round_flags[] = { + { FE_TONEAREST, "to nearest" }, +#ifdef FE_UPWARD + { FE_UPWARD, "upwards" }, +#endif +#ifdef FE_DOWNWARD + { FE_DOWNWARD, "downwards" }, +#endif + { FE_TOWARDZERO, "to zero" } +}; + +static void print_input(float input) +{ + char *in_fmt = fmt_f32(input); + printf("from single: %s\n", in_fmt); + free(in_fmt); +} + +static void convert_single_to_double(float input) +{ + double output; + char *out_fmt, *flag_fmt; + + feclearexcept(FE_ALL_EXCEPT); + + output = input; + + out_fmt = fmt_f64(output); + flag_fmt = fmt_flags(); + printf(" to double: %s (%s)\n", out_fmt, flag_fmt); + free(out_fmt); + free(flag_fmt); +} + +#define xstr(a) str(a) +#define str(a) #a + +#define CONVERT_SINGLE_TO_INT(TYPE, FMT) \ + static void convert_single_to_ ## TYPE(float input) \ + { \ + TYPE ## _t output; \ + char *flag_fmt; \ + const char to[] = "to " xstr(TYPE); \ + feclearexcept(FE_ALL_EXCEPT); \ + output = input; \ + flag_fmt = fmt_flags(); \ + printf("%11s: %" FMT " (%s)\n", to, output, flag_fmt); \ + free(flag_fmt); \ + } + +CONVERT_SINGLE_TO_INT( int32, PRId32) +CONVERT_SINGLE_TO_INT(uint32, PRId32) +CONVERT_SINGLE_TO_INT( int64, PRId64) +CONVERT_SINGLE_TO_INT(uint64, PRId64) + +int main(int argc, char *argv[argc]) +{ + int i, j, nums; + + nums = get_num_f32(); + + for (i = 0; i < ARRAY_SIZE(round_flags); ++i) { + if (fesetround(round_flags[i].flag) != 0) { + printf("### Rounding %s skipped\n", round_flags[i].desc); + continue; + } + printf("### Rounding %s\n", round_flags[i].desc); + for (j = 0; j < nums; j++) { + float input = get_f32(j); + print_input(input); + /* convert_single_to_half(input); */ + convert_single_to_double(input); + convert_single_to_int32(input); + convert_single_to_int64(input); + convert_single_to_uint32(input); + convert_single_to_uint64(input); + } + } + + return 0; +} diff --git a/tests/tcg/multiarch/float_helpers.c b/tests/tcg/multiarch/float_helpers.c new file mode 100644 index 0000000000..8ee7903c78 --- /dev/null +++ b/tests/tcg/multiarch/float_helpers.c @@ -0,0 +1,230 @@ +/* + * Common Float Helpers + * + * This contains a series of useful utility routines and a set of + * floating point constants useful for exercising the edge cases in + * floating point tests. + * + * Copyright (c) 2019 Linaro + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +/* we want additional float type definitions */ +#define __STDC_WANT_IEC_60559_BFP_EXT__ +#define __STDC_WANT_IEC_60559_TYPES_EXT__ + +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <inttypes.h> +#include <math.h> +#include <float.h> +#include <fenv.h> + +#include "float_helpers.h" + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +/* + * Half Precision Numbers + * + * Not yet well standardised so we return a plain uint16_t for now. + */ + +/* no handy defines for these numbers */ +static uint16_t f16_numbers[] = { + 0xffff, /* -NaN / AHP -Max */ + 0xfcff, /* -NaN / AHP */ + 0xfc01, /* -NaN / AHP */ + 0xfc00, /* -Inf */ + 0xfbff, /* -Max */ + 0xc000, /* -2 */ + 0xbc00, /* -1 */ + 0x8001, /* -MIN subnormal */ + 0x8000, /* -0 */ + 0x0000, /* +0 */ + 0x0001, /* MIN subnormal */ + 0x3c00, /* 1 */ + 0x7bff, /* Max */ + 0x7c00, /* Inf */ + 0x7c01, /* NaN / AHP */ + 0x7cff, /* NaN / AHP */ + 0x7fff, /* NaN / AHP +Max*/ +}; + +static const int num_f16 = ARRAY_SIZE(f16_numbers); + +int get_num_f16(void) +{ + return num_f16; +} + +uint16_t get_f16(int i) +{ + return f16_numbers[i % num_f16]; +} + +/* only display as hex */ +char *fmt_16(uint16_t num) +{ + char *fmt; + asprintf(&fmt, "f16(%#04x)", num); + return fmt; +} + +/* + * Single Precision Numbers + */ + +#ifndef SNANF +/* Signaling NaN macros, if supported. */ +# if __GNUC_PREREQ(3, 3) +# define SNANF (__builtin_nansf ("")) +# define SNAN (__builtin_nans ("")) +# define SNANL (__builtin_nansl ("")) +# endif +#endif + +static float f32_numbers[] = { + -SNANF, + -NAN, + -INFINITY, + -FLT_MAX, + -0x1.1874b2p+103, + -0x1.c0bab6p+99, + -0x1.31f75p-40, + -0x1.505444p-66, + -FLT_MIN, + 0.0, + FLT_MIN, + 0x1p-25, + 0x1.ffffe6p-25, /* min positive FP16 subnormal */ + 0x1.ff801ap-15, /* max subnormal FP16 */ + 0x1.00000cp-14, /* min positive normal FP16 */ + 1.0, + 0x1.004p+0, /* smallest float after 1.0 FP16 */ + 2.0, + M_E, M_PI, + 0x1.ffbep+15, + 0x1.ffcp+15, /* max FP16 */ + 0x1.ffc2p+15, + 0x1.ffbfp+16, + 0x1.ffcp+16, /* max AFP */ + 0x1.ffc1p+16, + 0x1.c0bab6p+99, + FLT_MAX, + INFINITY, + NAN, + SNANF +}; + +static const int num_f32 = ARRAY_SIZE(f32_numbers); + +int get_num_f32(void) +{ + return num_f32; +} + +float get_f32(int i) +{ + return f32_numbers[i % num_f32]; +} + +char *fmt_f32(float num) +{ + uint32_t single_as_hex = *(uint32_t *) # + char *fmt; + asprintf(&fmt, "f32(%02.20a:%#010x)", num, single_as_hex); + return fmt; +} + + +/* This allows us to initialise some doubles as pure hex */ +typedef union { + double d; + uint64_t h; +} test_doubles; + +static test_doubles f64_numbers[] = { + {SNAN}, + {-NAN}, + {-INFINITY}, + {-DBL_MAX}, + {-FLT_MAX-1.0}, + {-FLT_MAX}, + {-1.111E+31}, + {-1.111E+30}, /* half prec */ + {-2.0}, {-1.0}, + {-DBL_MIN}, + {-FLT_MIN}, + {0.0}, + {FLT_MIN}, + {2.98023224e-08}, + {5.96046E-8}, /* min positive FP16 subnormal */ + {6.09756E-5}, /* max subnormal FP16 */ + {6.10352E-5}, /* min positive normal FP16 */ + {1.0}, + {1.0009765625}, /* smallest float after 1.0 FP16 */ + {DBL_MIN}, + {1.3789972848607228e-308}, + {1.4914738736681624e-308}, + {1.0}, {2.0}, + {M_E}, {M_PI}, + {65503.0}, + {65504.0}, /* max FP16 */ + {65505.0}, + {131007.0}, + {131008.0}, /* max AFP */ + {131009.0}, + {.h = 0x41dfffffffc00000 }, /* to int = 0x7fffffff */ + {FLT_MAX}, + {FLT_MAX + 1.0}, + {DBL_MAX}, + {INFINITY}, + {NAN}, + {.h = 0x7ff0000000000001}, /* SNAN */ + {SNAN}, +}; + +static const int num_f64 = ARRAY_SIZE(f64_numbers); + +int get_num_f64(void) +{ + return num_f64; +} + +double get_f64(int i) +{ + return f64_numbers[i % num_f64].d; +} + +char *fmt_f64(double num) +{ + uint64_t double_as_hex = *(uint64_t *) # + char *fmt; + asprintf(&fmt, "f64(%02.20a:%#020" PRIx64 ")", num, double_as_hex); + return fmt; +} + +/* + * Float flags + */ +char *fmt_flags(void) +{ + int flags = fetestexcept(FE_ALL_EXCEPT); + char *fmt; + + if (flags) { + asprintf(&fmt, "%s%s%s%s%s", + flags & FE_OVERFLOW ? "OVERFLOW " : "", + flags & FE_UNDERFLOW ? "UNDERFLOW " : "", + flags & FE_DIVBYZERO ? "DIV0 " : "", + flags & FE_INEXACT ? "INEXACT " : "", + flags & FE_INVALID ? "INVALID" : ""); + } else { + asprintf(&fmt, "OK"); + } + + return fmt; +} diff --git a/tests/tcg/multiarch/float_helpers.h b/tests/tcg/multiarch/float_helpers.h new file mode 100644 index 0000000000..6337bc66c1 --- /dev/null +++ b/tests/tcg/multiarch/float_helpers.h @@ -0,0 +1,26 @@ +/* + * Common Float Helpers + * + * Copyright (c) 2019 Linaro + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include <inttypes.h> + +/* Number of constants in each table */ +int get_num_f16(void); +int get_num_f32(void); +int get_num_f64(void); + +/* Accessor helpers, overflows will automatically wrap */ +uint16_t get_f16(int i); /* use _Float16 when we can */ +float get_f32(int i); +double get_f64(int i); + +/* Return format strings, free after use */ +char * fmt_f16(uint16_t); +char * fmt_f32(float); +char * fmt_f64(double); +/* exception flags */ +char * fmt_flags(void); diff --git a/tests/tcg/multiarch/float_madds.c b/tests/tcg/multiarch/float_madds.c new file mode 100644 index 0000000000..eceb4ae38b --- /dev/null +++ b/tests/tcg/multiarch/float_madds.c @@ -0,0 +1,103 @@ +/* + * Fused Multiply Add (Single) + * + * Copyright (c) 2019 Linaro + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <float.h> +#include <fenv.h> + +#include "float_helpers.h" + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +typedef struct { + int flag; + char *desc; +} float_mapping; + +float_mapping round_flags[] = { + { FE_TONEAREST, "to nearest" }, +#ifdef FE_UPWARD + { FE_UPWARD, "upwards" }, +#endif +#ifdef FE_DOWNWARD + { FE_DOWNWARD, "downwards" }, +#endif + { FE_TOWARDZERO, "to zero" } +}; + + +static void print_inputs(float a, float b, float c) +{ + char *a_fmt, *b_fmt, *c_fmt; + + a_fmt = fmt_f32(a); + b_fmt = fmt_f32(b); + c_fmt = fmt_f32(c); + + printf("op : %s * %s + %s\n", a_fmt, b_fmt, c_fmt); + + free(a_fmt); + free(b_fmt); + free(c_fmt); +} + +static void print_result(float r, int j, int k) +{ + char *r_fmt, *flag_fmt; + + r_fmt = fmt_f32(r); + flag_fmt = fmt_flags(); + + printf("res: %s flags=%s (%d/%d)\n", r_fmt, flag_fmt, j, k); + + free(r_fmt); + free(flag_fmt); +} + +static void do_madds(float a, float b, float c, int j, int k) +{ + float r; + + print_inputs(a, b, c); + + feclearexcept(FE_ALL_EXCEPT); + r = __builtin_fmaf(a, b, c); + + print_result(r, j, k); +} + +int main(int argc, char *argv[argc]) +{ + int i, j, k, nums = get_num_f32(); + float a, b, c; + + for (i = 0; i < ARRAY_SIZE(round_flags); ++i) { + if (fesetround(round_flags[i].flag) != 0) { + printf("### Rounding %s skipped\n", round_flags[i].desc); + continue; + } + printf("### Rounding %s\n", round_flags[i].desc); + for (j = 0; j < nums; j++) { + for (k = 0; k < 3; k++) { + a = get_f32(j + ((k)%3)); + b = get_f32(j + ((k+1)%3)); + c = get_f32(j + ((k+2)%3)); + do_madds(a, b, c, j, k); + } + } + + /* From https://bugs.launchpad.net/qemu/+bug/1841491 */ + printf("# LP184149\n"); + do_madds(0x1.ffffffffffffcp-1022, 0x1.0000000000001p-1, 0x0.0000000000001p-1022, j, 0); + do_madds(0x8p-152, 0x8p-152, 0x8p-152, j+1, 0); + } + + return 0; +} diff --git a/tests/test-char.c b/tests/test-char.c index d62de1b088..45e42af290 100644 --- a/tests/test-char.c +++ b/tests/test-char.c @@ -1103,7 +1103,7 @@ static void char_socket_server_two_clients_test(gconstpointer opaque) } -#ifdef HAVE_CHARDEV_SERIAL +#if defined(HAVE_CHARDEV_SERIAL) && !defined(WIN32) static void char_serial_test(void) { QemuOpts *opts; @@ -1460,7 +1460,7 @@ int main(int argc, char **argv) #endif g_test_add_func("/char/udp", char_udp_test); -#ifdef HAVE_CHARDEV_SERIAL +#if defined(HAVE_CHARDEV_SERIAL) && !defined(WIN32) g_test_add_func("/char/serial", char_serial_test); #endif g_test_add_func("/char/hotswap", char_hotswap_test); diff --git a/tests/test-qga.c b/tests/test-qga.c index 891aa3d322..1ca49bbced 100644 --- a/tests/test-qga.c +++ b/tests/test-qga.c @@ -668,7 +668,7 @@ static void test_qga_blacklist(gconstpointer data) error = qdict_get_qdict(ret, "error"); class = qdict_get_try_str(error, "class"); desc = qdict_get_try_str(error, "desc"); - g_assert_cmpstr(class, ==, "GenericError"); + g_assert_cmpstr(class, ==, "CommandNotFound"); g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled")); qobject_unref(ret); @@ -677,7 +677,7 @@ static void test_qga_blacklist(gconstpointer data) error = qdict_get_qdict(ret, "error"); class = qdict_get_try_str(error, "class"); desc = qdict_get_try_str(error, "desc"); - g_assert_cmpstr(class, ==, "GenericError"); + g_assert_cmpstr(class, ==, "CommandNotFound"); g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled")); qobject_unref(ret); diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c index ab389f42da..36fdf5b115 100644 --- a/tests/test-qmp-cmds.c +++ b/tests/test-qmp-cmds.c @@ -97,6 +97,10 @@ void qmp_boxed_union(UserDefListUnion *arg, Error **errp) { } +void qmp_boxed_empty(Empty1 *arg, Error **errp) +{ +} + __org_qemu_x_Union1 *qmp___org_qemu_x_command(__org_qemu_x_EnumList *a, __org_qemu_x_StructList *b, __org_qemu_x_Union2 *c, diff --git a/tests/usb-hcd-ehci-test.c b/tests/usb-hcd-ehci-test.c index 8bc3e44189..5251d539e9 100644 --- a/tests/usb-hcd-ehci-test.c +++ b/tests/usb-hcd-ehci-test.c @@ -8,7 +8,7 @@ */ #include "qemu/osdep.h" -#include "libqtest.h" +#include "libqtest-single.h" #include "libqos/pci-pc.h" #include "hw/usb/uhci-regs.h" #include "hw/usb/ehci-regs.h" @@ -139,7 +139,7 @@ static void pci_ehci_port_3_hotplug(void) static void pci_ehci_port_hotplug(void) { - usb_test_hotplug("ich9-ehci-1", "3", pci_ehci_port_3_hotplug); + usb_test_hotplug(global_qtest, "ich9-ehci-1", "3", pci_ehci_port_3_hotplug); } diff --git a/trace-events b/trace-events index 823a4ae64e..20821ba545 100644 --- a/trace-events +++ b/trace-events @@ -52,14 +52,14 @@ dma_map_wait(void *dbs) "dbs=%p" find_ram_offset(uint64_t size, uint64_t offset) "size: 0x%" PRIx64 " @ 0x%" PRIx64 find_ram_offset_loop(uint64_t size, uint64_t candidate, uint64_t offset, uint64_t next, uint64_t mingap) "trying size: 0x%" PRIx64 " @ 0x%" PRIx64 ", offset: 0x%" PRIx64" next: 0x%" PRIx64 " mingap: 0x%" PRIx64 ram_block_discard_range(const char *rbname, void *hva, size_t length, bool need_madvise, bool need_fallocate, int ret) "%s@%p + 0x%zx: madvise: %d fallocate: %d ret: %d" +memory_notdirty_write_access(uint64_t vaddr, uint64_t ram_addr, unsigned size) "0x%" PRIx64 " ram_addr 0x%" PRIx64 " size %u" +memory_notdirty_set_dirty(uint64_t vaddr) "0x%" PRIx64 # memory.c memory_region_ops_read(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u" memory_region_ops_write(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u" memory_region_subpage_read(int cpu_index, void *mr, uint64_t offset, uint64_t value, unsigned size) "cpu %d mr %p offset 0x%"PRIx64" value 0x%"PRIx64" size %u" memory_region_subpage_write(int cpu_index, void *mr, uint64_t offset, uint64_t value, unsigned size) "cpu %d mr %p offset 0x%"PRIx64" value 0x%"PRIx64" size %u" -memory_region_tb_read(int cpu_index, uint64_t addr, uint64_t value, unsigned size) "cpu %d addr 0x%"PRIx64" value 0x%"PRIx64" size %u" -memory_region_tb_write(int cpu_index, uint64_t addr, uint64_t value, unsigned size) "cpu %d addr 0x%"PRIx64" value 0x%"PRIx64" size %u" memory_region_ram_device_read(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u" memory_region_ram_device_write(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u" flatview_new(void *view, void *root) "%p (root %p)" diff --git a/util/async.c b/util/async.c index 4e4c7af51e..ca83e32c7f 100644 --- a/util/async.c +++ b/util/async.c @@ -354,7 +354,11 @@ void aio_notify(AioContext *ctx) void aio_notify_accept(AioContext *ctx) { - if (atomic_xchg(&ctx->notified, false)) { + if (atomic_xchg(&ctx->notified, false) +#ifdef WIN32 + || true +#endif + ) { event_notifier_test_and_clear(&ctx->notifier); } } diff --git a/util/notify.c b/util/notify.c index aee8d93cb0..76bab212ae 100644 --- a/util/notify.c +++ b/util/notify.c @@ -40,6 +40,11 @@ void notifier_list_notify(NotifierList *list, void *data) } } +bool notifier_list_empty(NotifierList *list) +{ + return QLIST_EMPTY(&list->notifiers); +} + void notifier_with_return_list_init(NotifierWithReturnList *list) { QLIST_INIT(&list->notifiers); diff --git a/util/oslib-win32.c b/util/oslib-win32.c index c62cd4328c..886e400d6a 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -585,7 +585,11 @@ int qemu_connect_wrap(int sockfd, const struct sockaddr *addr, int ret; ret = connect(sockfd, addr, addrlen); if (ret < 0) { - errno = socket_error(); + if (WSAGetLastError() == WSAEWOULDBLOCK) { + errno = EINPROGRESS; + } else { + errno = socket_error(); + } } return ret; } diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 98ff3a1cce..bcc06d0e01 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -461,12 +461,13 @@ int inet_connect_saddr(InetSocketAddress *saddr, Error **errp) } } + freeaddrinfo(res); + if (sock < 0) { error_propagate(errp, local_err); + return sock; } - freeaddrinfo(res); - if (saddr->keep_alive) { int val = 1; int ret = qemu_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, @@ -3554,6 +3554,11 @@ int main(int argc, char **argv, char **envp) g_slist_free(accel_list); exit(0); } + if (optarg && strchr(optarg, ':')) { + error_report("Don't use ':' with -accel, " + "use -M accel=... for now instead"); + exit(1); + } opts = qemu_opts_create(qemu_find_opts("machine"), NULL, false, &error_abort); qemu_opt_set(opts, "accel", optarg, &error_abort); |